Verification of JSON web tokens

Tokens are signed with asymmetric cryptography, using the RS256 signing algorithm. This means that the payload is hashed using the SHA256 hashing function and then signed with a private RSA key. The key length is 2048b which should be enough for the foreseeable future.

An API granting access to any resource must verify the token before granting access. The Auth application exposes the algorithm and public key using the JWKS standard:

https://auth.openimp.com/authtest/keys.json is the public key for the development server, while https://auth.openimp.com/keys.json is the public key for the production server.

Each endpoint returns keys in this format:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "254e2669331d112ef0d6d6e81e02815c",
      "alg": "RS256",
      "use": "sig",
      "n": "AMscnzNpnb3KurGxd-.....asgwSYP9g0M",
      "e": "AQAB",
      "publicKey": "LS0tLS1C..........................................................................IEAdsWS0tLS0tCg"
    },
    {
      "kty": "RSA",
      "kid": "e82f27e4c03a2e3a929582d39ecd3af2",
      "alg": "RS256",
      "use": "sig",
      "n": "ANzNv4t1XKI3BlVMr....g6g7OFQSb6Wkc",
      "e": "AQAB",
      "publicKey": "LS0tLS1C..........................................................................IEtFWS0tLS0tCg"
    },
    {
      "kty": "RSA",
      "kid": "29ce29aa426d662a12d588121f9110d4",
      "alg": "RS256",
      "use": "sig",
      "n": "AN1m7-hSG-6NAqiTG....aQj3K-tBTr75U",
      "e": "AQAB",
      "publicKey": "LS0tLS1C..........................................................................IEAdsWS0tLS0tCg"
    }
  ]
}

The data format is described in the RFC 7517 - JSON Web Key (JWK). For interoperability purposes we also add a publicKey attribute which contains a base64url encoded PEM public key.

Other ways to obtain KEYS

The AuthApplication also supports the ASAP standard Atlassian S2S Authentication Protocol Specification and its modification (see here https://s2sauth.bitbucket.io/spec/)

Individual keys can be obtained using these routes:

The {kid} params are also case insensitive.

Sample JS Node / Express Implementation

const Express = require('express')
const jwt = require('express-jwt')
const jwksRsa = require('jwks-rsa')
var jwtAuthz = require('express-jwt-authz')


const app = new Express()

// Check the JWT, including checking the JWT signature using the JWKS endpoint
app.use(
  jwt({
    secret: jwksRsa.expressJwtSecret({
      cache: true,
      cacheMaxAge: 60 * 60 * 1000, // 1 hour
      rateLimit: true,
      jwksRequestsPerMinute: 5,
      jwksUri: 'https://auth.openimp.com/authtest/keys.json' // testing server
      // jwksUri: 'https://auth.openimp.com/keys.json' // production server
    }),

    // The following checks for issuer and audience are optional
    // Validate the issuer
    issuer: 'https://auth.openimp.com',

    // Validate the audience
    audience: 'humans', // specified in the application definition
    algorithms: ['RS256']
  })
)



// Check the JWT scope
app.use(
  jwtAuthz([ 'sample-application' ])
)

app.get('/', function(req, res) {
  return res.send({ status: 'OK', user: req.user })
})

app.listen(4000)
console.info('API Server started on port 4000')

The JWT middleware checks the token validity: https://github.com/auth0/express-jwt

The jwksRsa module takes care of downloading the respective keys from the JWKS endpoint. The keys are identified by the kid attribute in the JWT header. It also takes care of caching and rate limiting: https://github.com/auth0/node-jwks-rsa

The optional jwtAuthz validates scopes: https://github.com/auth0/express-jwt-authz


Created: Sat Apr 20 2024 04:59:16 GMT+0000 (Coordinated Universal Time)
Build ID: 125548