awslabs / aws-jwt-verify

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

[QUESTION] AWS Support says this library cannot be used for Cognito within an ALB... is that true? #71

Closed shackbarth closed 2 years ago

shackbarth commented 2 years ago

Question Having engaged AWS Support to deal with an "JWT string does not consist of exactly 3 parts (header, payload, signature)" error from this package, AWS Support responded, and I quote: because the ALB returned JWT token format includes a header, payload, and signature that are base64 URL encoded and includes padding characters at the end. The JWT signature is ECDSA + P-256 + SHA256, and because the standard libraries are not compatible with padding that is included in the Application Load Balancer authentication token in JWT format, you are not able to verify these tokens using the standard library 'aws-jwt-verify'.

This seems really outlandish, because this package certainly seems to be game to verify JWTs coming from Cognito, even if Cognito is operating within an ALB. I've seen plenty of griping about the ALB padding issue (e.g. https://github.com/auth0/node-jws/pull/84) but I figured this package would be able to work out-of-the-box, as it were. Am I wrong about that?

Versions Which version of aws-jwt-verify are you using? 3.0.0 Are you using the library in Node.js or in the Web browser? Node.js If Node.js, which version of Node.js are you using? (Should be at least 14) 16.13.1 If Web browser, which web browser and which version of it are you using? N/A If using TypeScript, which version of TypeScript are you using? (Should be at least 4) N/A

hakanson commented 2 years ago

Short answer: That is true as of now.

Longer answer: The current version of AWS JWT Verify can be used for "verifying JWTs signed by Amazon Cognito, and any OIDC-compatible IDP that signs JWTs with RS256 / RS384 / RS512." As you quote from the User claims encoding and signature verification section of "Authenticate users using an Application Load Balancer" - those tokens have a JWT signature using ECDSA + P-256 + SHA256, and not using RSA.

Also, note this comment from that same section of the ALB docs:

The load balancer signs the user claim so that applications can verify the signature and verify that the claims were sent by the load balancer.

It appears the ALB is taking the claim set from the Cognito token and constructing a new JWT formatted token, with it's own header and own kid which can be validated at https://public-keys.auth.elb.{region}.amazonaws.com/{key-id}

{
   "alg": "algorithm",
   "kid": "12345678-1234-1234-1234-123456789012",
   "signer": "arn:aws:elasticloadbalancing:region-code:account-id:loadbalancer/app/load-balancer-name/load-balancer-id", 
   "iss": "url",
   "client": "client-id",
   "exp": "expiration"
}

This is a legitimate request for AWS JWT Verify to natively validate these ALB tokens. Possibly via an ALBJwtVerifier which could handle that padding, verify the ECDSA signature, and retrieve keys from the custom endpoints. I need to take a closer look at how these tokens are constructed and come back to this issue with additional comments.

shackbarth commented 2 years ago

Thanks for the clarification! My use case (using Cognito within an ALB listener rule) must be more obscure than I thought it was, for there to be so little discussion about it, but at least it's memorialized on this issue. What with the ALB repackaging the JWT, it's now clear to me that the work that I have to do on Fargate to verify the user claims basically has nothing at all to do with Cognito anymore.

rdkls commented 1 year ago

Hi @hakanson some more info, the padding does seem to be the only issue.

There's a thread from 2020 on it here https://github.com/auth0/node-jws/pull/84

I tried jose and it does validate these tokens, discussion here: https://github.com/panva/jose/discussions/30

https://github.com/panva/jose

pschwyter commented 1 year ago

Just ran into this as well, using ALB with Cognito.

In case you want another solution (using jsonwebtoken): https://github.com/auth0/node-jsonwebtoken/issues/514#issuecomment-461100470

Basically the solution side steps the encoding issue by splitting up responsibilities:

  1. Use jws to verify the signature and payload
  2. Convert the base64 encoded token to base64url and pass it to jsonwebtoken's decode

We use decode since it skips verification and jws since it doesn't validate the payload 😅