How to verify JWT from AWS Cognito in the API backend?

后端 未结 10 574
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-12 11:17

I\'m building a system consisting of an Angular2 single page app and a REST API running on ECS. The API runs on .Net/Nancy, but that might well change.

I would like

10条回答
  •  情歌与酒
    2020-12-12 11:36

    Execute an Authorization Code Grant Flow

    Assuming that you:

    • have correctly configured a user pool in AWS Cognito, and
    • are able to signup/login and get an access code via:

      https://.auth.us-west-2.amazoncognito.com/login?response_type=code&client_id=&redirect_uri=
      

    Your browser should redirect to ?code=4dd94e4f-3323-471e-af0f-dc52a8fe98a0


    Now you need to pass that code to your back-end and have it request a token for you.

    POST https://.auth.us-west-2.amazoncognito.com/oauth2/token

    • set your Authorization header to Basic and use username= and password= per your app client configured in AWS Cognito
    • set the following in your request body:
      • grant_type=authorization_code
      • code=
      • client_id=
      • redirect_uri=

    If successful, your back-end should receive a set of base64 encoded tokens.

    {
        id_token: '...',
        access_token: '...',
        refresh_token: '...',
        expires_in: 3600,
        token_type: 'Bearer'
    }
    

    Now, according to the documentation, your back-end should validate the JWT signature by:

    1. Decoding the ID token
    2. Comparing the local key ID (kid) to the public kid
    3. Using the public key to verify the signature using your JWT library.

    Since AWS Cognito generates two pairs of RSA cryptograpic keys for each user pool, you need to figure out which key was used to encrypt the token.

    Here's a NodeJS snippet that demonstrates verifying a JWT.

    import jsonwebtoken from 'jsonwebtoken'
    import jwkToPem from 'jwk-to-pem'
    
    const jsonWebKeys = [  // from https://cognito-idp.us-west-2.amazonaws.com//.well-known/jwks.json
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "ABCDEFGHIJKLMNOPabc/1A2B3CZ5x6y7MA56Cy+6ubf=",
            "kty": "RSA",
            "n": "...",
            "use": "sig"
        },
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=",
            "kty": "RSA",
            "n": "...",
            "use": "sig"
        }
    ]
    
    function validateToken(token) {
        const header = decodeTokenHeader(token);  // {"kid":"XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=", "alg": "RS256"}
        const jsonWebKey = getJsonWebKeyWithKID(header.kid);
        verifyJsonWebTokenSignature(token, jsonWebKey, (err, decodedToken) => {
            if (err) {
                console.error(err);
            } else {
                console.log(decodedToken);
            }
        })
    }
    
    function decodeTokenHeader(token) {
        const [headerEncoded] = token.split('.');
        const buff = new Buffer(headerEncoded, 'base64');
        const text = buff.toString('ascii');
        return JSON.parse(text);
    }
    
    function getJsonWebKeyWithKID(kid) {
        for (let jwk of jsonWebKeys) {
            if (jwk.kid === kid) {
                return jwk;
            }
        }
        return null
    }
    
    function verifyJsonWebTokenSignature(token, jsonWebKey, clbk) {
        const pem = jwkToPem(jsonWebKey);
        jsonwebtoken.verify(token, pem, {algorithms: ['RS256']}, (err, decodedToken) => clbk(err, decodedToken))
    }
    
    
    validateToken('xxxxxxxxx.XXXXXXXX.xxxxxxxx')
    

提交回复
热议问题