Expand my Community achievements bar.

Dive into Adobe Summit 2024! Explore curated list of AEM sessions & labs, register, connect with experts, ask questions, engage, and share insights. Don't miss the excitement.
SOLVED

Verify JWT Token - Registered OAuth Clients

Avatar

Level 3

I am looking for documentation on the correct approach/pattern for JWT OAuth validation when using the Registered OAuth Clients in AEM. I have searched the internet and I have not found any good examples of how to validate the JWT OAuth Registered Client token.

 

I understand the flow from a 3rd Party OAuth Authentication server (ie: FaceBook, Google), but I am looking for the pattern when using the OOTB Registered OAuth Clients in AEM (/libs/granite/oauth/content/clients.html).

 

Can anyone please provide me with some direction or an approved validation pattern.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

@jarvislukow - I never tried this but should be possible with some effort - Extend the OAuth2ServerAuthenticationHandler

 

The OAuth2ServerAuthenticationHandler is responsibe for validating the token and sending the AuthenticationInfo object  on sucessfull validation/login(null response incase of validation/login failure) - The class is available in "Adobe Granite OAuth Server(com.adobe.granite.oauth.server)" bundle

 

You can create a custom AuthenticationHandler(extend - adjust the ranking) and respond with Auth Fail status code from extractCredentials method for token validation errors - currently extractCredentials respond with null for invalid tokens

 

e.g 

 

if (validAccessToken) {

 

.......

 

}else

{

request.setAttribute("j_reason", "invalid_token");
return AuthenticationInfo.FAIL_AUTH;

}

 

Regards

Albin I

www.albinsblog.com

View solution in original post

13 Replies

Avatar

Level 3

Thanks.  I have read this.  But, I'll have a read though it again... this time in more detail.
Thanks again

Avatar

Level 3

@Albin_Issac Turns out I was overthinking the solution,  but to be fair there is so little documentation on this pattern.  Using the ScopeWithPrivileges does work as expected...  with one issue.  AEM returns a 404 when the token is not valid.  Can this be modified to return a 404 is the resource is not found, and a 401 if the token is not valid?

Avatar

Correct answer by
Community Advisor

@jarvislukow - I never tried this but should be possible with some effort - Extend the OAuth2ServerAuthenticationHandler

 

The OAuth2ServerAuthenticationHandler is responsibe for validating the token and sending the AuthenticationInfo object  on sucessfull validation/login(null response incase of validation/login failure) - The class is available in "Adobe Granite OAuth Server(com.adobe.granite.oauth.server)" bundle

 

You can create a custom AuthenticationHandler(extend - adjust the ranking) and respond with Auth Fail status code from extractCredentials method for token validation errors - currently extractCredentials respond with null for invalid tokens

 

e.g 

 

if (validAccessToken) {

 

.......

 

}else

{

request.setAttribute("j_reason", "invalid_token");
return AuthenticationInfo.FAIL_AUTH;

}

 

Regards

Albin I

www.albinsblog.com

Avatar

Level 3

@Albin_Issac I have this working for the most part now - In my flow I am using the server-server integration, and I am curious about the user and user permissions.  

 

In my working code, and in your example, when I decode the access_token returned from the Adobe Granite server the subject is always set to admin. 

"sub":"admin"

This is regardless of the subject passed with the token request.  It looks like the user name (subject) admin is parsed out of the accessToken.

final String userId = OAuth2Helper.getSubject(accessToken);

And this is used as the base for the user session.  If this is the case, how can we restrict custom scopes?  

 

Am I missing something?  I assumed that the session created in AEM would be essentially an anonymous access plus what was defined in the scope.

Avatar

Community Advisor

How are you generating the JWT token? Have you specified the username in the sub while generating token?

 

Also, please parse the generated token through jwt.io and see if the user name is available(Refer to the blog for more details - https://medium.com/tech-learnings/how-to-manage-the-protected-aem-resources-through-oauth-2-0-851ce4...)

 

Regards

Albin I

www.albinsblog.com

Avatar

Level 3

Regardless of including the "sub" attribute in the JWT Bearer token, the generated access token always changes the sub to admin. 

 

Since I am following the server-server pattern, I am using the urn:ietf:params:oauth:grant-type:jwt-bearer grant type.  

 

In the example you referenced, if you decode the generated access token for the server-server flow I also see the sub was converted to admin:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJnNmIzajl2aTk4bDM5ZmFvNzFpdmc0aDlraC1xM2dydGdoaCIsImlzcyI6IkFkb2JlIEdyYW5pdGUiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTU5NzI3NzYwNSwiaWF0IjoxNTk3Mjc0MDA1LCJzY29wZSI6ImRhbV9yZWFkIiwiY3R5IjoiYXQifQ.g-AXNazPxnAP1VbB8Ym1NB_UFW2MuCmYvsPWuZY-jfQ
{"alg":"HS256","typ":"JWT"}{"aud":"g6b3j9vi98l39fao71ivg4h9kh-q3grtghh","iss":"Adobe Granite","sub":"admin","exp":1597277605,"iat":1597274005,"scope":"dam_read","cty":"at"}

Maybe this doesn't matter... but I am confused what user a session is actually for if successful.

Avatar

Community Advisor

No this is the token referred in my blog for server to server OAuth(JWT)

 

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQ1MDIvb2F1dGgvdG9rZW4iLCJpc3MiOiJnNmIzajl2aTk4bDM5ZmFvNzFpdmc0aDlraC1xM2dydGdoaCIsInN1YiI6ImFsYmlub2F1dGgiLCJleHAiOjE1OTcyNzM4OTA5NDA2LCJpYXQiOjE1OTcyNzM4MDk0MDYsInNjb3BlIjoiZGFtX3JlYWQiLCJjdHkiOiJjb2RlIn0.EmXLGX9RK-i4OPh-kA8YSTxi8PSJxVtk7uWsYLcMqXY4Z-ZI6pJK_1uLZdJbFxurs3tLqkg300w6w3M99PTrHZg54J2s9SafZyB7psAh6K8ycEvJDHsUDD1ovZvMfQ__tqhMC8yzGFlODLWaAx095fVHO-ce4pewxdzwv3TQK593xwjtwL_hPRqLkjy6Kvt6Cu0TEJd6YFoMNiftca9KxIMEG9fMOpNkHe4rIo_oSqdmiDzbqBZ-0P_3j4gDO_AYnULF9h42NHOrgAxOucfwZbfxgHc8UODUiLw3f1Mw9WGK9POzdFPeruHcknjRf4J60BwestDbFjfHb_8owXAJwA

 

The sub value is specified as albinoauth when i try to parse the token throughhttps://jwt.io/

 

Albin_Issac_0-1631036388488.png

 

 

Regards

Albin I

www.albinsblog.com

 

 

 

 

Avatar

Level 3

Yes, the bearer token (or assertion) does contain the sub, like your example.  But in the generated access token, in your example and in my code, the sub is converted to admin.

 

So, for the actual content request when the access token is validated how does the scoped permissions get bound to the request.  I see the scopes being added via:

 

OAuth2Helper.addACLEntries(oauthServiceSession, oauthUser.getPrincipal(), user, OAuth2Helper.getScopeSetFromNames(oAuth2ResourceServer, scopes), true);

but if I remove the included scope to not include a secure path, the request still returns a 200. 

 

I assumed that the defined resource paths in the scopeWithPrivileges class would control the actual resource security... but it seems that is not the case.  It seems to be adding the paths to an existing user?

 

 

 

Avatar

Level 3

@Albin_Issac I see, the authentication handler is actually adding the newly created oauth users as members of the everyone group.  I thought it was going to use anonymous for some reason...  but everyone is better than using the admin group which I thought it was  

 

The last question I have is regarding scopes - Is it possible register multiple paths in one scope? Or use a wildcard/regex pattern?  For example I would like to register the following paths to one scope:

/content/dam/projectName/secure/en_ca
/content/dam/projectName/secure/fr_ca

Is there an approach to bind multiple paths to one scope?

/content/dam/projectName/secure/*

 

Thanks for your help on this. 

Avatar

Community Advisor

Looks to be this is the default behaviour, getResourcePath(User user) returns signle path as string

 

Please post the extended AuthHandler here if possible, may helps others with same requirement.

 

Regards

Albin I

www.albinsblog.com