This library implements token verification for the SOLID-OIDC Request Flow as of today (Editor’s Draft, 2 November 2022) in plain Java, (... sips coffee ...).
The SolidOidcTokenVerifier implements all the functionality for the authentication/authorization server (as) to derive a boolean decision if the client is authenticated or not.
Maybe we will add support for an identity provider as well at some point in time. No promises, though.
Example usage:
// client id token as base64 // dont forget to strip "DPoP " from the header :)
String idToken = "eyJraWQiOiIxMjMiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJzb2xpZCIsInN1YiI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTk5OS93ZWJpZCIsIndlYmlkIjoiaHR0cDovL2xvY2FsaG9zdDo5OTk5L3dlYmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5OTk5IiwiY25mIjp7ImprdCI6ImNyb1BHZEZ6RElla0c4LVg2RTFBLTFfdmNsREVhREJyMElTWUJVSXZESFEifSwiZXhwIjoxNjY5OTAyNTM1LCJpYXQiOjE2Njk5MDI1MzF9.m-Am2MYAntzXKKL2JcGMy5XRCHL4aOngGKhdv7dnhd1TGXM066yUEiy1pxapNHfuFo_eBfQRYq2cPaDRJvZrZg";
// client dpop token as base64
String dpopToken = "eyJraWQiOiI0MiIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwia2lkIjoiNDIiLCJuIjoiNUJ2aFZMXzA0bnlhcUVmSkRaaGZnaC1mMkhuZzdxWnB0bVFjMjRsRUlNT0ZuY3JyVmFnQ0lSRkU0ZWdHNXRFcWF6b1FzY18xN0ZhZW5VSzFIWDBXeTA4WGpXaWliSjkxdU1qZnBVNEJoZzM1Xy15RzlnQXhLX3ZYYl9sRmtjRGFvaFRCcU9lRWJfNXFuaVhwcURaV05ILXhTRjR1dExvY0VtbUlUMXJRSzNqV3BnQ1B1Y25IT1VpTkZMYXZNRlNEV041NFVXZUE2dVY1WVdvUWlrbmJBWU5uQlhOLWE3dW5FZmdTbEtDSFBXZ2k4cXdVc3hiX3NtV0RsQ2RnS28xbkFwSENGeTN5TjE0OVdQSkRXd2w0T1BLQjBnNEh0RDMzc3hPZzJhUENjSjR6NGdYMjUxV0w4Q20tMVItMVotX0lhZHpIUlNnY1czSmpvMDZ1RU9lTFJRIn19.eyJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL3V2ZHNsLnNvbGlkd2ViLm9yZy9pbmJveC8ifQ.hgA6JorJEpytgApXP321z3KcJJO2byA4KG5po2Af8NiKjTtXskHdpFPcZfgqIoFdxT5H6sf2UQNq4SwheeObrpXZUn1zX8sCyhnN-7Ve0e0i1Z6VNdbPU-4gK2T46ZDJIfhIZztqme_46_qe7lYKSNptcXQsoaPmLM_6IJpkYxxdCT6hUiXDWSuikWB_LeFEsIefqw0e0ufWHj7ZNvA_GI2ApSsrSFdDZDHWA9jXTy4bmwcUJqTpi7njgBB4--aJqWMHUg_ktYoH27J0mMa2BsIVtp669UEwvhgsOGKlOi1x-g5Bselr2E8zGtCbsntqXtLhlCgs_TZpLJcB7Y7Yqw";
// the URI the token were used for
URI httpRequestUri = new URI("https://example.org");
// the method the token were used with
String httpRequestMethod = "GET";
// SOLID-ODIC Verifier
SolidOidcTokenVerifier soidcVerifier = new SolidOidcTokenVerifier();
// looking for the verification result
URI webid = null;
try {
// will never return something else than the webid
webid = soidcVerifier.verify(idToken, dpopToken, httpRequestUri, httpRequestMethod);
// if there is an issue, an exception is generated
} catch (SolidOidcException e) {
// any error related to SOLID-OIDC is caught here
System.err.println("\t[ ERROR ]\t" + e.getMessage());
} // other exceptions may indicate other errors, e.g. unavailable issuer, webId
// profile etc
// print out the result
System.out.println("\t[ INFO ]\tVerified: " + ((webid != null) ? webid.toString() : "false"));
// happy hackingWant to run the example directly? Sure, after cloning this repository, with Maven:
mvn package
mvn exec:java
Sure, after cloning this repository, with Maven:
mvn package
Then, find the test coverage report at target/site/jacoco/index.html.
Starting at step 5, ending at step 12.
sequenceDiagram
participant WebID as 👩 End-User's WebID Document
participant OP as 👩 OpenID Provider
participant Client as ⚙️ Client
participant AS as ☁️ Authorization Server
participant RS as ☁️ Resource Server
Client->>RS: 1. Discover Authorization Server
RS->>Client: Responds 401 with as_uri
Client->>AS: 2. Requests AS configuration
AS->>Client: AS configuration
note over Client: 3. Creates a DPoP header token
Client->>AS: 4. Request Access Token
note over AS: 5. Checks ID Token expirations
note over AS: 6. Checks DPoP Token url and method
note over AS: 6.1. (Optional) Checks DPoP token unique identifier
note over AS: 7. Checks DPoP signature against Access Token
AS->>WebID: 8. Retrieves WebID Document
WebID->>AS: Profile
note over AS: 9. Checks Issuer
AS->>OP: 10. Retrieves OP configuration
OP->>AS: OP configuration
AS->>OP: 11. Requests JWKS
OP->>AS: JWKS
note over AS: 12. Checks access token signature validity
AS->>Client: 13. Access Token Response
Client->>RS: 14. Sends Request with Access Token
note over AS, RS: Have pre-established usage of Access Tokens
RS->>Client: 15. Returns Result
We rely on nimbus-jose-jwt for checking the JWTs and on Apache Jena for handling the RDF of the WebID profile. (I guess you could also do it manually if you want.)