Validating that the Identity ID passed in an open ID token matches an identity in the specified Identity Pool
ryantomaselli opened this issue · 2 comments
Hey guys; thanks for this very useful library!
Question
I am currently using an Cognito Identity Pool to handle users that haven't been authenticated yet. The app is a multi-tenanted app with each tenant having its own User Pool and Identity Pool.
I currently generate the token on the client side like so:
const { Token: openIdToken } = await new AWS.CognitoIdentity().getOpenIdToken({
IdentityId: identityId
}).promise()
When I decode the token in my Lambda Authorizer it looks like so:
{
sub: ''us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
aud: 'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
iss: 'https://cognito-identity.amazonaws.com',
amr: [ 'unauthenticated' ],
exp: 1662753731,
iat: 1662753131
}
The sub value is the Identity ID for the user and the aud value is the Identity Pool ID.
If I want to make sure that this token is valid I need to make sure that the Identity ID in the token matches an identity in the Identity Pool specified by aud
Am I correct in thinking that I need to call the CognitoIdentity.listIdentities method, which I need potentially page through, in order to determine whether there is and identity that matches the Identity ID in the token?
For reference: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentity.html#listIdentities-property
Thanks for any pointers.
Versions
Which version of aws-jwt-verify
are you using? ^3.1.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
If using TypeScript, which version of TypeScript are you using?: ^4.7.4
To verify an identity pool JWT you would follow the usual JWT verification steps such as: check signature is valid, check not expired, check iss
is what you expect, check aud
is what you expect. These steps are all carried out for you by the JwtRsaVerifier
from aws-jwt-verify
. (You can't use the CognitoJwtVerifier
as that is for User Pool JWTs, not Identity Pool JWTs)
Checking that the sub
actually is an existing user, i.e. that it exists in the identity pool -- I recommend to not do this, you want to trust that it is, if the JWT is indeed valid. The JWT is created and signed by the identity pool, and it will only do so for identities known to the identity pool.
Also, listIdentities
is a control plane operation, subject to smaller rate limits. You don't want to call that as part of normal authentication verification flows, as those usually have higher TPS than the rate limit allows.
Note the IETF says this link:
Similarly, when the JWT contains a "sub" (subject) claim, the
application MUST validate that the subject value corresponds to a
valid subject and/or issuer-subject pair at the application. This
may include confirming that the issuer is trusted by the application.
If the issuer, subject, or the pair are invalid, the application MUST
reject the JWT.
Which means you should not test whether the sub
exists at the IDP (the identity pool) but whether the sub
was indeed registered in your application. (In some DB or whatever that you as application developer own) --> But since anonymous users in Identity Pools get new sub
s every time you call GetIdentity
, this is not applicable to anonymous users. I.e. skip sub
check for them.
Hope that makes sense, let me know if it helps.
@ottokruse thanks for this detailed response...it clears things up and certainly helps.
Cheers