Subject is not in access token
Closed this issue · 5 comments
Hi, thanks for this example. When I'm trying this on my server, I'm not getting the subject back in the access token so the validation fails.
Do you know what I could be missing?
// get the subject from the access token var subjectClaim = result.Claims.FirstOrDefault(c => c.Type == "sub"); if (subjectClaim == null) { context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Subject token must contain sub value."); return; }
It looks like this might be because I call my API from another server with client_credentials without user interaction. This is then a access_token, not a id_token. Any thoughts on how to get around this?
Hi John,
if you're using the client credentials flow you cannot get a sub value as there is no user involved... to get an access token with a sub value, you need to use one of the flows that require user interaction.
The idea behind that on behalf of / token exchange flow is exchanging one token for another one while keeping the current user's identity, so the identity can flow downstream. If there is no user, there's no user identity and thus no need for the on behalf of flow.
Thanks Kevin.
So if I wanted to store API Keys for a user to do this instead, what would you suggest?
Creating a page for users to manage API Keys and store them in the IdentityUserToken table, then using these in an external application to access the API?
The external API needs to run with no user interaction and I have to know the tenant id and the user roles in the API call.
I would suggest not using API keys at all. These are essentially "everlasting passwords" that allow immediate access to an API "on behalf of" the user - that should be avoided. Tokens exist to mitigate the issues with API keys.
The client application (external application) that needs to access your external API would have to validate the user's credentials at least once, ie: it must start an OIDC flow (today, that probably means code flow + PKCE protection) that results in an access token (containing the user roles/tenant id) to access your API. The client should then safely store that access token together with a refresh token. If the refresh token has a long lifetime, it can be used for a long time to get a new access token to access your API. Eventually however, the user will have to authenticate again - but that's a good thing :)
Hope this helps!
Thank you very much, this is super helpful!
I totally get what you are saying, however, with an API for tenants I'm just trying to verify that the user has rights to the tenant they are accessing. Kind of like a scope, but dynamic per user. I can't have the user log in once in a while as this is a server to server communication where they upload data specific to this tenant.
I just need a way for the API to get access to the tenant id for the client_credentials to verify they are not writing to the wrong tenant, but I don't see a way to do that, I don't even know who the user is that is calling the API which I think is strange.
In every other aspect of my solution, the IDS4 server works great, it's just when accessing an API resource from a server to server scenario.
I'm afraid you're trying to do something that's not possible... if you need to execute a task on behalf of the user because it needs to know something about the user (like the tenant (s)he belongs to), you need the user to be involved at least once. Once that's been done, you can work with refresh tokens, with token exchange, ... there are lots of things you can do to ensure that your tokens stay valid and correctly get delivered downstream, from API to API to API etc, but you need that initial user involvement.
Without user involvement it's not possible to do this, unless you start linking "tenants", "users", ... to client credentials, or some other workaround - it'll work, but it'll remain a workaround - a misuse of the standard. I know it happens, it'll work, but it's not the best way to do it :)