Search code examples
typescriptamazon-web-servicesjwtamazon-cognito

Amazon Cognito ID Decoding


I'm building a web app where I'm authenticating users using the AWS Hosted UI, which would return to me a jwt token. Now I'm trying to develop such that I can decode that token to retrieve the user id for the user that would have logged in using the AWS Hosted UI so I can render their data from DynamoDB using their UserID, which is the partition key for all of their data. I've looked into documentation on how to Decode the jwt tokens in TypeScript but nothing seems to work. Can someone please help me and guide me in the right direction / guide me to code examples that I can refer to implement this?

*Note: I've looked at this documentation -> https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.ts but didn't have any luck with it.

Thank You!


Solution

  • If you're using TypeScript 4 or higher I recommend looking into the aws-jwt-verify repo: https://github.com/awslabs/aws-jwt-verify.

    This is a JavaScript library for verifying JWTs signed by Amazon Cognito, and any OIDC-compatible IDP that signs JWTs with RS256 / RS384 / RS512. This library can be used with Node.js 14 or higher (both CommonJS and ESM supported). If used with TypeScript, TypeScript 4 or higher is required.

    This might be your quickest path forward. The basic usage example would work for you. Not only will this validate the token for you, but it will decode it and return the JWT claims.

    Here's an example where ideally you would provide the encoded JWT to the payload constant:

    import { CognitoJwtVerifier } from "aws-jwt-verify";
    
    const verifier = CognitoJwtVerifier.create({
      userPoolId: "<user_pool_id>",
      tokenUse: "access",
      clientId: "<client_id>",
    });
    
    try {
      const payload = await verifier.verify(
        "eyJraWQeyJhdF9oYXNoIjoidk..." // the JWT as string
      );
      console.log("Token is valid. Payload:", payload);
    } catch {
      console.log("Token not valid!");
    }
    

    If the token is valid, your response would look like this:

    Token is valid. Payload: {
      sub: '0145dc99-d44e-4195-ae17-exampleSUB',
      iss: 'https://cognito-idp.<region>.amazonaws.com/<user-pool-id>',
      client_id: '7qfali14b8oq2rexampleAppClient',
      origin_jti: '486b02b1-d9ad-4551-9fb8-exampleOriginJTI',
      event_id: '40bc33fc-6582-40ed-b719-exampleEventID',
      token_use: 'access',
      scope: '<scopes>',
      auth_time: 17114000,
      exp: 17114000,
      iat: 17114000,
      jti: 'c538d8f9-9144-40ea-9482-exampleJTI',
      username: '0145dc99-d44e-4195-ae17-exampleSUB'
    }
    

    Since you mentioned you're intending to use the JWT issued from Hosted UI, I would highly recommend using the aws-jwt-verify library. This way you're validating and decoding the JWT at the same time.

    If you're just outright wanting to decode the token you could do something similar to this:

    import { decomposeUnverifiedJwt } from "aws-jwt-verify/jwt";
    
    const { payload } = decomposeUnverifiedJwt(
      "eyJraWQeyJhdF9oYXNoIjoidk..." // the JWT as string
    );
    console.log(payload);
    

    This would produce the example response:

    {
      sub: '0145dc99-d44e-4195-ae17-exampleSUB',
      iss: 'https://cognito-idp.<region>.amazonaws.com/<user-pool-id>',
      client_id: '7qfali14b8oq2rexampleAppClient',
      origin_jti: '486b02b1-d9ad-4551-9fb8-exampleOriginJTI',
      event_id: '40bc33fc-6582-40ed-b719-exampleEventID',
      token_use: 'access',
      scope: '<scopes>',
      auth_time: 17114000,
      exp: 17114000,
      iat: 17114000,
      jti: 'c538d8f9-9144-40ea-9482-exampleJTI',
      username: '0145dc99-d44e-4195-ae17-exampleSUB'
    }
    

    Again, unless you can absolutely trust a JWT then you can go the route of just decoding the token, but I would always recommend you verify it first.

    Here's another example, specific to Express: https://github.com/awslabs/aws-jwt-verify?tab=readme-ov-file#express