damienbod / angular-auth-oidc-client

npm package for OpenID Connect, OAuth Code Flow with PKCE, Refresh tokens, Implicit Flow
https://www.npmjs.com/package/angular-auth-oidc-client
MIT License
1.15k stars 433 forks source link

[Question]: How to retrieve the scopes allowed for the user? #1845

Open CesarD opened 1 year ago

CesarD commented 1 year ago

Version: 16.0.1

How can I retrieve the scopes that the user is allowed to access? In the UserData I can only see the usual claims like the profile ones, email, sub, etc., but can't see the roles or the claims the user has access to. Is there any way to retrieve this with this library?

flyingfishflash commented 1 year ago

I'm not an expert, but in my experience the authentication server (keycloak, zitadel, etc) would need to be configured to include this in addition to the standard response. Either in the id/access tokens it generates or the userinfo endpoint itself. Edit: Additionally you may be required to include a specific scope in the OIDC configuration to ensure the roles are included in the information provided by the userinfo endpoint.

CesarD commented 1 year ago

Hi @flyingfishflash. Yes, indeed, such mechanism exists and I'm actually implementing it. The scopes and the roles are coming in the Access Token and are even logged in the [DEBUG] logs performed by the library such as below:

AuthResult '{
  "access_token": "[removed for brevity]",
  "expires_in": 300,
  "refresh_expires_in": 0,
  "token_type": "Bearer",
  "id_token": "[removed for brevity]",
  "not-before-policy": 0,
  "session_state": "ad5586f3-d856-4a30-95db-b22027462044",
  "scope": "openid email my-api companies:read companies:write profile",
  "state": "d782a86d862c803b9903e3bed10c2765bcmdvO6e7"
}'.
      AuthCallback created, begin token validation

The problem for me is that they are not being returned or exposed in any of the interfaces the library has: for example I can't access these values through neither the OidcSecurityService, the PublicEventsService events nor even through the UserData observables, so there's no chance for me to easily and elegantly take this data and, for example, store it in my app state without having to resort to pick the token from the configured storage, parse it and all that drill which is very cumbersome when the library already exposes such a nice API for other stuff.

Worth to mention this data was exposed in other libraries such us oidc-client-js and oidc-client-ts, and it was very easy to get and useful to have for different use cases.

FabianGosebrink commented 1 year ago

You should be able to get the complete AuthResult with getauthenticationresult() . Are the scopes on there in your case?

CesarD commented 1 year ago

You should be able to get the complete AuthResult with getauthenticationresult() . Are the scopes on there in your case?

You're right, that method does return the scopes and other data from the auth result, I was just missing calling it because it got me confused with the event NewAuthenticationResult (which one could very well expect to additionally bring that same information without having to call getAuthenticationResult separately; perhaps a suggestion for improvement?).

What I don't see anywhere are the roles. I am indeed asking for them by including the roles scope in the list of scopes and they are coming in the AccessToken; although perhaps is worth to note that I'm working with Keycloak at the moment and it returns the app roles in a JSON structure like:

"resource_access": {
    "my-api": {
      "roles": [
        "Administrator",
        "Customer"
      ]
    }
  },

Though I understand that it should be protocol compliant. Should this work?

Thanks!

flyingfishflash commented 1 year ago

image

Are you sure you don't need getUserData()? At least for Zitadel, this is where the configured roles returned by the identity service are included. I pass the scope 'urn:zitadel:iam:org:projects:roles' initially, and Zitadel returns all the roles the authenticated user possesses. Maybe Keycloak works differently. It's also possible that this library doesn't parse token for non-standard data, and in my case it this is being pulled from the well-known .../userinfo endpoint. I haven't tried including the data on the token, which is more efficient.

CesarD commented 1 year ago

Well, like I said, the roles come in the Access Token as expected, they just aren't mapped against the userData that I retrieve with any of the exposed methods from OidcSecurityService. And if I enable the library option to retrieve user data through the userinfo endpoint I get a 401 response, but the rest works just fine. With oidc-client-ts/js I never got that issue. Although this library should be able to pull the roles from the access token nevertheless just like the other libs can do the same.

CesarD commented 1 year ago

To provide some further feedback on this, for the time being I have resorted to use .getPayloadFromAccessToken() to pull the data required from the accessToken directly. It would have been interesting that the library already provided these remaining claims in the userData observable as those are some user specific claims that would make sense to come all together.