How do I use Cognito with Express-gateway for token validation

70 Views Asked by At

I have drafted the following architecture

Proposed architechture

I'm having issues on the validate JWT part on the gateway (Not sure if this is how it's supposed to work).

From what I understand, when a request gets to the gateway, Express Gateway does the JWT validation against the credentials we've set up in the config.

Here is a snippet of gateway.config.yml:

policies:
  - proxy
  - logging
  - jwt
  - oauth2

pipelines:
  service1:
    apiEndpoints:
      - service1
    policies:
      - logging:
      - oauth2:
          - action:
              - jwt:
                  subject: 'cognito-app-client-id'
                  algorithms: [ 'alg' ]
                  checkCredentialExistence: false/true
                  issuer: 'cognito-issuer'
                  secretOrPublicKey: 'pub key from cognito'
                  audience: 'cognito-app-client-id'
                  clientId: 'cognito-app-client-id'
                  clientSecret: 'cognito-app-client-secret'

Note that secretOrPublicKey was retrieved from this URL: https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json and it returned the following:

{
    "keys": [
        {
            "alg": "",
            "e": "",
            "kid": "",
            "kty": "",
            "n": "",
            "use": ""
        }
    ]
}

To test my endpoint, I made the following request to the gateway including the JWT I got from Cognito.

curl --location --request POST 'https://mygateway/service1' \
--header 'Authorization: Bearer eyYg...' \
--data ''

However I get a 401 (Unauthorized).

Somewhere, somehow, I'm missing something. I just don't know if I'm misunderstanding the whole flow, or I'm not setting up my config properly.

Does anyone have an idea of what I'm possibly missing, or the possible solution?

1

There are 1 best solutions below

0
On

Here is what I did to fix the issue.

Fetch my Cognito app-client JWK from this URL: https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json

Response:

{
    "keys": [
        {
            "alg": "",
            "e": "",
            "kid": "",
            "kty": "",
            "n": "",
            "use": ""
        }
    ]
}

Convert the JWK to a .pem file (there are online tools for this), but for confidentiality purposes, I wrote this python script to do the conversion:

import json
from jwcrypto import jwk

jwk_data = {
            "alg": "replace with actual value from jwk",
            "e": "replace with actual value from jwk",
            "kid": "replace with actual value from jwk",
            "kty": "replace with actual value from jwk",
            "n": "replace with actual value from jwk",
            "use": "replace with actual value from jwk"
        }

key = jwk.JWK(**jwk_data)
public_key = key.export_to_pem()

with open('public_key.pem', 'wb') as pem_file:
    pem_file.write(public_key)

Of course you'll need to install jwcrypto with

python3 -m pip install jwcrypto

After generating the .pem file, I updated my gateway.config.yml as follow:

pipelines:
service1:
  apiEndpoints:
    - service1
  policies:
    - logging:
    - jwt:
        - action:
            secretOrPublicKeyFile: cert/public_key.pem  #cert is the folder where my .pem file is located.
            checkCredentialExistence: false
    - service1:    

Making a cURL request to the gateway with the correct JWT now returns the desired output.

curl --location --request POST 'https://mygateway/service1' \
--header 'Authorization: Bearer eyYg...' \
--data ''