Search code examples
aws-sdkamazon-cognitoaws-sdk-go

Verifying Cognito access tokens server-side


I've got a Cognito access token server-side using AdminInitiateAuth (AWS SDK for Go) and I'm storing that in a session cookie. I'm assuming I need to validate that token on every subsequent request. Do I need to call out to Cognito for every request, or can I validate the token in my app server-side?


Solution

  • "OpenID is a decentralized authentication protocol" So you don't have to query a DB server or the Cognito server to verify it because of the asymmetric RSA approach.

    I had the same issue with OpenID tokens. I'm using Cognito to register to sign-In and sign-up my users. initially, I could authorize them by using an API gateway authenticator without issues but later I decided to move this in a Kubernetes backend.

    The best idea I found around is from: How to verify a JWT Token from AWS Cognito in Go? thread

    and a good Python example from https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.py

    you'll need the public key in order to verify the JWT token

    JWT tokens have a based64 URL encoded JSON format with three fields <header>.<payload>.<signature>. In the payload field you can find the iss field to search the the "kid" public key before trying to do the verification.

    testparse := strings.Split(tokenid, ".")
    base64decode, err := base64.RawURLEncoding.DecodeString(testparse[1])
    fmt.Println("Claims:", string(base64decode))
    

    or better use "github.com/dgrijalva/jwt-go" & "github.com/lestrrat-go/jwx/jwk" to do something like:

    jwt.Parse(yourTokenStr, getKeyFunction)

    then in your getKeyFunction() you can do:

    fmt.Println("Header: Alg:", token.Header["alg"], ", Kid: ", token.Header["kid"])
    
    claims := token.Claims.(jwt.MapClaims)
    
    // Print unverified claims
    for key, value := range claims {
        log.Printf("%s\t: %v\n", key, value)
        if key == "iss" {
            // AWS cognito uses /.well-known/jwks.json path for the pub key
            jwksURL = value.(string) + "/.well-known/jwks.json"
        }
    }
    ...
    

    If your jwt.Parse(yourTokenStr, getKeyFunction) won't return any error the token is valid.

    The errors you can get for example are "Token is expired" or (for my case) a more generic "crypto/rsa: verification error" if it is an expired Token_ID.