awslabs / aws-jwt-verify

JS library for verifying JWTs signed by Amazon Cognito, and any OIDC-compatible IDP that signs JWTs with RS256, RS384, RS512, ES256, ES384, and ES512
Apache License 2.0
632 stars 45 forks source link

[BUG] Handle Revoked Access and ID Tokens #173

Closed cjsuthanthira closed 2 months ago

cjsuthanthira commented 2 months ago

This library needs to return that the tokens are revoked after revoking the refresh token

ottokruse commented 2 months ago

Please read the explanation in https://github.com/awslabs/aws-jwt-verify/issues/151 and share any new insights. Thanks!

cjsuthanthira commented 2 months ago

Please read the explanation in #151 and share any new insights. Thanks!

Hi, checking just the JWT can be a default option. But we should have a flag, like upstream: true, that can reach out to Cognito and check if the token is revoked. Right now, the workaround is to use aws-jwt-verify and then call Cognito's GetUser API with Access Token to check if the Access Token is revoked.

Since this is a library supported by AWS, I would like to check if AWS Cognito Team can provide us with an option to check upstream for both Access Token and ID Token.

ottokruse commented 2 months ago

Why do you want this? It's very clear we could add that to this library, but why should we? Let's be more concrete: what's the threat model you're thinking of?

cjsuthanthira commented 2 months ago

A user signs into a portal containing multiple apps each sharing the same token. When a user signs out from an application the ID and Access tokens are revoked. The other apps using the same token need to understand that the tokens are revoked.

ottokruse commented 2 months ago

Thank you.

Follow up question. Where are tokens stored? Upon sign-out you should delete the tokens locally so they would not be able to be used for other apps. Why doesn't this "simply" work for you?

JWTs being stolen / leaked is another matter, but that must also be protected against while the user is still signed in--so it's not per se related to detecting sign outs right.

cjsuthanthira commented 2 months ago

We delete tokens in the app where sign out happens. But in the other apps using the same token which are opened in another browser tab, when a user takes any action (or on window.onfocus), we want to check the token and sign them out from these other app as well.

Stolen JWTs calling our APIs directly is another scenario we will check.

Our option right now is calling aws-jwt-verify and then GET-USER API. So, I wanted to check if this library can reduce this two-step process into one using an additional flag when calling the verify method.

ottokruse commented 2 months ago

we want to check the token and sign them out from these other app as well.

Do these apps use the same token storage? If yes, e.g. localstorage, then if in one app you clear the tokens from localstorage (upon signout), then other tabs can simply check token storage as well and when there's no tokens assume the user is not yet signed in. Or broadcast an event to all tabs to re-check auth status.

I presume you use the same client ID in all these apps (to use a single set of tokens across all of them), so then AWS Amplify JS would store these tokens in browser localstorage, and all your apps (for that user pool and client ID) across all tabs would actually be using the same set of items in localstorage.

cjsuthanthira commented 2 months ago

The different apps are unable to share the localStorage as they run in different sub-domains / domains.

The main portal passes the tokens to the other apps through the URL. And I'm not able to manually set the tokens properly into AWS Amplify JS in the other apps. So, I'm unable to use AWS Amplify JS in these other apps. I'm using aws-jwt-verify to check the tokens, but I need to call GET-USER to additionally check for revoked tokens in order to sign out.

Is there a way to manually set the tokens into AWS Amplify JS?

If yes, then I can use the AWS Amplify JS's auth-status check to find that the tokens are revoked and sign out. I would not need aws-jwt-verify in the front end.

I would still need to do both aws-jwt-verify and GET-USER API call in the backend though.

ottokruse commented 2 months ago

The different apps are unable to share the localStorage as they run in different sub-domains / domains.

Got it.

Is there a way to manually set the tokens into AWS Amplify JS?

Don't know of the top of my head.

It sounds like what you're doing in the UI may be pretty specific and not a core use case to aws-jwt-verify, however backend validation surely is. What is the threat model though? Why don't you use tokens with a more limited expiry (maybe 15 minutes), and delete them upon signout? That saves you from having to do the GetUser call (which only works for access tokens) that takes additional latency and creates requests against Cognito that may hit throttling limits if too many in parallel.

Thanks for the detail so far, just trying to uncover the real reason you want to verify upstream with Cognito, what scenario's "are you afraid of" so to speak. (We can think of them ourselves but rather like to hear from you, a user)

cjsuthanthira commented 2 months ago

For the frontend, there is no threat. We want to logout the user from App2 by identifying that the tokens are revoked (even if valid) because the user signed out from App1, when both apps are using the same token.

For the backend, say we do keep the token's validity to 5 minutes. We want to ensure that the token is not a revoked token even if valid. It is not a major threat. Just that the frontend App2 will still be able to make a call to the backend with valid but revoked tokens.

cjsuthanthira commented 2 months ago
  1. We will try to not use aws-jwt-verify from the frontend
  2. We will use tokens with validity of 5 minutes
ottokruse commented 2 months ago

That's probably the easiest and most scalable way!

  1. Delete the tokens from the frontend upon signout
  2. Sync the delete to your other apps (using a mechanism of your choosing, eg URL fragment) --> this realizes "global" sign out of your apps
  3. Short token expiry --> always a good idea
cjsuthanthira commented 2 months ago

That's probably the easiest and most scalable way!

  1. Delete the tokens from the frontend upon signout
  2. Sync the delete to your other apps (using a mechanism of your choosing, eg URL fragment) --> this realizes "global" sign out of your apps
  3. Short token expiry --> always a good idea

Thank you for your inputs

ottokruse commented 2 months ago

Note that a sign out with Amplify JS would also call https://docs.aws.amazon.com/cognito/latest/developerguide/token-revocation.html for the refresh token (as well as delete the token locally)––which is a good idea