Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support introspection of ID tokens #410

Closed
mitar opened this issue Apr 2, 2020 · 28 comments
Closed

Support introspection of ID tokens #410

mitar opened this issue Apr 2, 2020 · 28 comments
Labels
stale Feedback from one or more authors is required to proceed.

Comments

@mitar
Copy link
Contributor

mitar commented Apr 2, 2020

Is your feature request related to a problem? Please describe.

It looks like introspection of ID tokens does not work through the introspect handler?

Describe the solution you'd like

That it does.

Describe alternatives you've considered

I could validate ID tokens locally by myself, but it is also useful to have an API endpoint to do so.

Additional context

Okta does so: https://developer.okta.com/docs/reference/api/oidc/

@aeneasr
Copy link
Member

aeneasr commented Apr 11, 2020

Is there an open standard to this? I don't quite remember but I think some OpenID Connect spec was covering this. Maybe it would make sense to go down that road? The okta solution seems to be "proprietary" to their API.

@mitar
Copy link
Contributor Author

mitar commented Apr 11, 2020

So rfc7662 just covers access and refresh tokens, others are out of the scope. But it is dealing only with OAuth anyway. I could not find anything about ID token introspection in OpenID Connect specs. But that is a bit strange, given that OIDC adds a new token type. So not sure what to do about this.

@aeneasr
Copy link
Member

aeneasr commented Apr 12, 2020

The rationale is that there is no need to do introspection if the token is not opaque and you have access to the keys. This seems to be really dependent on the provider, Google has the tokeninfo endpoint for that which doesn't follow any IETF or OID convention.

@mitar
Copy link
Contributor Author

mitar commented Apr 12, 2020

For my use case, it is more about validation than introspection. One can always decode it, but to check if token was not revoked, you have to call introspection endpoint, no? So it is about trusting the authorization server to do the validation instead of you doing it locally. For some use cases where you do not care so much about extra round trip time, this might be OK.

See also this spec. This is not exactly the same thing as we are discussing here, but has some of similar rationale for it:

However, there are use cases where the resource server requires stronger assurance that the authorization server issued the token introspection response for an access token, including cases where the authorization server assumes liability for the content of the token introspection response.

This is similar to what I am thinking. I want the server to tell me that everything is OK. That it is not the client making this decision, which might have the clock wrong (on purpose or by mistake) to have token expiration badly checked. And client cannot check that the token was revoked.

Is there any other endpoint to check if an ID token has been revoked?

@aeneasr
Copy link
Member

aeneasr commented Apr 13, 2020

For my use case, it is more about validation than introspection. One can always decode it, but to check if token was not revoked, you have to call introspection endpoint, no? So it is about trusting the authorization server to do the validation instead of you doing it locally. For some use cases where you do not care so much about extra round trip time, this might be OK.

Is there any other endpoint to check if an ID token has been revoked?

ID Tokens can not be revoked. They are proof that someone logged in and is who they say they are with a timestamp of when that happened. ID Tokens do not establish a shared "login" session between the RP and OP.

@mitar
Copy link
Contributor Author

mitar commented Apr 13, 2020

You are right. There is whole set of other specs about session management and ways to logout. In fact, checking with none response type (#409) is one of ways to determine if user is still logged in.

@aeneasr
Copy link
Member

aeneasr commented Apr 16, 2020

Yup - so I take it this can be closed then?

@mitar
Copy link
Contributor Author

mitar commented Apr 16, 2020

I mean, I would still like to have this in, like Okta does, so that one can call it to verify the token, like I wrote above:

This is similar to what I am thinking. I want the server to tell me that everything is OK. That it is not the client making this decision, which might have the clock wrong (on purpose or by mistake) to have token expiration badly checked.

It is true that this does not check for revocation, as you cannot revoke ID tokens, as you explained to me. But the rest, that you can offload token validation to server, I find it still useful. (For example, I use Kong and have a Kong plugin, so if I can just call my server to validate the token it seems much easier than encoding token validation in the plugin.)

@aeneasr
Copy link
Member

aeneasr commented Apr 25, 2020

The core problem I see is that the OAuth2 Token Introspection spec is targeted at Resource Servers. So when a Resource Server receives a token, it checks against the Authorization Server if the token is (still) valid and what its payload is. The payload is typical internal session state and might contain things like roles, permissions, and so on. Because this stuff is "internal" and confidential in 99% of use cases, Introspection is typically not exposed to the outside world. For me at least I don't know any big OAuth2 Providers (not talking about IDaaS like Auth0) where this is implemented according to spec. Some providers do have a check token endpoint though.

That's why Hydra exposes this endpoint at the Admin API only!

However, ID Tokens are external readable state (per definition because JWT). It therefore - for me - contradicts what OAuth2 Token Introspection solves and may confuse people into exposing the OAuth2 Token Introspection to the outside world.

Keep in mind that the Access Token is something that's only useful on the Resource Server side. The client doesn't really care what it's content is as long as it gives access to something. This is different from what an ID Token represents.

I think Google has an endpoint to decode/verify ID Tokens - maybe they follow some spec?

@mitar
Copy link
Contributor Author

mitar commented Apr 25, 2020

You are right, they have tokeninfo endpoint. It is mentioned here as well. That looks to me like introspect endpoint in fact, like what I am requesting here, if I just open https://oauth2.googleapis.com/tokeninfo I get:

{

    "error": "invalid_token",
    "error_description": "Either access_token, id_token, or token_handle required"

}

But I do not see any standard being referenced anywhere. It just returns parsed ID token it seems (if validated).

Thanks for explaining more here though. I completely agree with everything you wrote. I see this really just as a debug tool and something one can quickly use to make sure things work. Calling this endpoint on regular basis is unnecessary load anyway.

@mitar
Copy link
Contributor Author

mitar commented Apr 26, 2020

Because this stuff is "internal" and confidential in 99% of use cases, Introspection is typically not exposed to the outside world.

Sorry, after rereading your comment I realized that I forgot about my initial motivation behind this issue and focused on my current motivation (frontend development). I have currently addressed this need by in meantime implementing my own handler which does something similar, so I forgot about that.

So the reason why I opened this issue in the first place was in fact for this "internal" use. Our frontend obtains ID token for the user, when user signs-in, and then we pass that ID token in Authorization header to the server and API there. We use Kong then to validate the ID token and map it to simpler HTTP header which is then used by internal services, which do not have to validate tokens anymore, but just trust what Kong decides. Now, we could do token validation inside Kong plugin (and some standard OAuth already exist), but to me it looked even simpler (if it would exist) that I would simply delegate to "standard" introspect handler to determine if provided token is same or not. In this way I do not have to worry about public keys, caching of them, and so on. I call the introspect endpoint and I know that it is the only source of truth. So I tried that and I was surprised that it did not work on ID tokens.

In addition to this use case, I think it is useful for debugging by clients/frontend, as I described above.

@mitar
Copy link
Contributor Author

mitar commented May 1, 2020

I am aware that we could also obtain access token, but ID token has some useful information (like subject) in JWT which then allows us to just map the token without additional database query.

@aeneasr
Copy link
Member

aeneasr commented Oct 29, 2020

I thought about this more and I think this is very dangerous. An ID Token is fundamentally different from an access token. The former can not be revoked while the latter can (in real time). The former is proof of authentication, the latter proof of authorization. The introspection spec does not return the concrete token type (only Bearer) and must check all registered strategies (e.g. first check access token, then refresh token, then id token) which could lead an authorization server wrongfully accepting an ID Token as proof of authorization.

This is already problematic for refresh_tokens as they could theoretically be used as long living credentials and I think the RFC does not explain what needs to be done here.

@mitar
Copy link
Contributor Author

mitar commented Oct 29, 2020

The former can not be revoked while the latter can (in real time).

Unless the latter is JWT as well and use use stateless introspection. Which we do support. (With a big warning.)

which could lead an authorization server wrongfully accepting an ID Token as proof of authorization.

I think this just shows that if you are using introspection endpoint to validate tokens (to check if they should be accepted) then you should also pass audience parameter to check that the given token is for expected audience. This solves the problem of one using access token meant for one audience to gain access to another audience (both tokens are valid, just audience is different). And same holds for ID tokens and access tokens. If you worry you could confuse them (you use introspection endpoint to validate tokens to determine access) then you should pass audience parameter.

So my proposal would be:

  • We should add audience parameter to the introspection endpoint. If somebody is using it to validate tokens to determine access, they should pass both scope and audience parameters. This is the only way to be safe.
  • Thus, we can support ID token introspection.

@aeneasr
Copy link
Member

aeneasr commented Oct 29, 2020

I think this just shows that if you are using introspection endpoint to validate tokens (to check if they should be accepted) then you should also pass audience parameter to check that the given token is for expected audience. This solves the problem of one using access token meant for one audience to gain access to another audience (both tokens are valid, just audience is different). And same holds for ID tokens and access tokens. If you worry you could confuse them (you use introspection endpoint to validate tokens to determine access) then you should pass audience parameter.

This is problematic because aud or audience is not standardised in OAuth2. It's a claim in JWT but there are actually no standards around how you would request the audience. Thus, imposing this requirement means that we're bending the spec. I understand the reason, but the real-world application might be difficult. What do you think?

@mitar
Copy link
Contributor Author

mitar commented Oct 29, 2020

Same holds for current scope parameter to introspect endpoint, no? That is also not by the spec? So I think the whole use of introspect endpoint to validate something beyond expiration time and correct signature seems to be out of spec?

@mitar
Copy link
Contributor Author

mitar commented Nov 4, 2020

(For everyone reading this, see also this thread for initial discussion before it was moved here.)

@github-actions
Copy link

I am marking this issue as stale as it has not received any engagement from the community or maintainers in over half a year. That does not imply that the issue has no merit! If you feel strongly about this issue

  • open a PR referencing and resolving the issue;
  • leave a comment on it and discuss ideas how you could contribute towards resolving it;
  • open a new issue with updated details and a plan on resolving the issue.

We are cleaning up issues every now and then, primarily to keep the 4000+ issues in our backlog in check and to prevent maintainer burnout. Burnout in open source maintainership is a widespread and serious issue. It can lead to severe personal and health issues as well as enabling catastrophic attack vectors.

Thank you for your understanding and to anyone who participated in the issue! 🙏✌️

If you feel strongly about this issues and have ideas on resolving it, please comment. Otherwise it will be closed in 30 days!

@github-actions github-actions bot added the stale Feedback from one or more authors is required to proceed. label Sep 21, 2021
@mitar
Copy link
Contributor Author

mitar commented Oct 21, 2021

So I am still interested in this, but there was no conclusion if this should be implemented. See my proposal above.

@aeneasr
Copy link
Member

aeneasr commented Oct 21, 2021

I re-read the points and still stand by my initial comment. Introspection is very clearly defined as:

This specification defines a method for a protected resource to query
an OAuth 2.0 authorization server to determine the active state of an
OAuth 2.0 token and to determine meta-information about this token.
OAuth 2.0 deployments can use this method to convey information about
the authorization context of the token from the authorization server
to the protected resource.

That, by definition, excludes ID Tokens for the already mentioned issues. I think the userinfo endpoint might be able to handle this iirc.

@mitar
Copy link
Contributor Author

mitar commented Oct 21, 2021

So are you then planing to remove scope argument to the introspection endpoint? Because that is non-standard as well?

Also, I would like to point out that it says:

the active state of an OAuth 2.0 token and to determine meta-information about this token

Not OpenID Connect token, but any OAuth 2.0 token, ID tokens are OAuth 2.0 tokens, no? So to determine if it is active and determine meta-information about the token, you should be able to use introspection endpoint?

@aeneasr
Copy link
Member

aeneasr commented Oct 21, 2021

There is a difference between doing something dangerous (using proof of authentication in the context of protected resources which need proof of authorization) and adding convenience features (token is only valid if it also has this scope).

ID tokens are OAuth 2.0 tokens, no

OpenID Connect ID Tokens are for sure no OAuth2 tokens and they have a totally different intent and meaning.

  • Access Token: Proof of Authorization for Resource Servers / Protected Resources
  • ID Token: Proof of Authentication for Relying Parties

@mitar
Copy link
Contributor Author

mitar commented Oct 21, 2021

Thank you for replying here. I will try my last time to explain why I think my proposal is a good change and what exactly is my proposal, because it has evolved since the initial description of the issue. My current proposal is:

Introspection endpoint gets an optional audience argument which makes so that the passed token has to have audience among its granted audiences.

This addresses few issues:

  • A fosite deployment might be granting access tokens to different audiences and the protected resource wants to make sure the access token is really for that resource (and its audience) and not for some other. This is a big issue currently. And in fact motivated by our own use case where we have different audiences granted by our SSO based on which product the user is using. We are not using introspection endpoint to protect resources but are doing our own validation so this is not a direct issue for us. But it motivates for me this change (and helped me better understand the issue at hand).
  • For stateless JWT introspector, there is no way to know if it got an access token or ID token, see here. So we are already supporting ID token introspection with stateless JWT introspector. To make that JWT introspector secure, an audience argument must be passed. (We could add this as a warning to documentation similarly to how we have a warning for state-less JWT strategy already.)

To me it follows (and we might disagree here) that:

  • To be consistent, also other introspectors could take ID token as input and return it as valid only if you passed the audience argument matching the ID token.
    • This could be implemented as additional handler, which would be opt-in then for users of fosite.

So the original topic of this issue would be in my view opt-in, if you pass audience argument of the relaying party and ID token, then and only then the introspection endpoint would check its validity and return its payload. This does not open any security issues you are describing.

In my view, audience should be a required argument. But probably we cannot make it so given that it is non-standard.

@aeneasr
Copy link
Member

aeneasr commented Oct 29, 2021

Thank you for the explanation, I understand your proposal better now.

I do agree with your idea that it improves the approach as you need to provide the audience, which makes the check explicit. But I disagree that the ID token‘s purpose is aligning with the definition of introspection:

This specification defines a method for a protected resource (NOT delegated client) to query
an OAuth 2.0 authorization server to determine the active state of an
OAuth 2.0 token and to determine meta-information about this token.
OAuth 2.0 deployments can use this method to convey information about
the authorization context (NOT authentication context) of the token from the authorization server
to the protected resource (NOT delegated client).

So this proposal contradicts several pieces of the specification in my understanding, regardless of how we work around it.

And true, for JWT strategies this is an issue and also why we discourage use of JWTs for access tokens! We should anyhow add something like token_use to the claims to improve the security of the verification.

@mitar
Copy link
Contributor Author

mitar commented Oct 29, 2021

Should I open another issue for adding audience parameter to introspection endpoint (for access tokens).

And I hear you what you say about a strict interpretation of the spec. But I think what I am asking for is a logical extrapolation, because the spec you are citing is OAuth spec and not OpenID Connect spec. Which is also one many other implementations do:

Anyway, I said I will not drill here more so I am stopping. :-)

@aeneasr
Copy link
Member

aeneasr commented Nov 1, 2021

Should I open another issue for adding audience parameter to introspection endpoint (for access tokens).

or even a PR! :)

Google has tokeninfo endpoint which to me looks like introspection endpoint and it accepts ID token

I think Google's approach makes sense as that endpoint is there solely for ID Token introspection! I looked through the specs because It hought /userinfo surely had an ID token introspection mechanism, but apparently not so! IMO that endpoint would be best suited for this though...

@mitar
Copy link
Contributor Author

mitar commented Nov 3, 2021

BTW, OpenID Connect working group aligns with your perspective: https://bitbucket.org/openid/connect/issues/1350/support-for-id-tokens-in-introspection

@aeneasr
Copy link
Member

aeneasr commented Nov 4, 2021

Thank you for following up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Feedback from one or more authors is required to proceed.
Projects
None yet
Development

No branches or pull requests

2 participants