When implementing and testing the package in our project an unexpected error response & statuscode was observed.
I tried a few different use cases to observe what the application would be returning.
Basic JWT Token
When sending a basic dummy jwt token taken from jwt.io looking like this.
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
It responds with the object below which is a perfectly valid response. (note no kid
is present in the request token header here)
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Authorization token is invalid: secret or public key must be provided"
}
Invalid Issuer
I then sent a token that contained my regular auth0 domain as the issuer while the app was registered with my custom domain as the issuer.
The token looked like this
// Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "<kid>"
}
// Payload
{
"iss": "https://<tenant>.eu.auth0.com/",
"sub": "<subject>",
"aud": "<api audience>,
"iat": 1618481452,
"exp": 1618567852,
"azp": "<party>",
"gty": "client-credentials"
}
The response was the object below, again a valid response (a bit more info as to why the token was invalid might've been nice but was pretty easily found by adding some log statements to the file)
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid token."
}
Token from a different tenant
However this is the part where it get's weird. When sending a request to the API using a token granted by a different tenant like the one posted below.
// Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "<kid>"
}
// Payload
{
"iss": "<other tennant>",
"sub": "<subject>",
"aud": "<other api audience>,
"iat": 1618230875,
"exp": 1618317275,
"azp": "<party>",
"gty": "client-credentials"
}
The response given is
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "Something went wrong"
}
and the log saying No matching key found in the set. Error: No matching key found in the set.
From looking at what's happening it seems like it goes and searches the domain specified in the app.register(fastifyAuth0Verify, {})
for a key with the kid
from the token header.
However as this kid
will not be present in the <domain>/.well-known/jwks.json
it is unable to find a key.
in the index.js
file this snippet can be found
if (!key) {
// Mark the key as missing
cache.set(cacheKey, null)
throw new Error(errorMessages.missingKey)
}
key will in fact be undefined as the jwks.json
does not contain a key with the specified kid
. The throw error causes it to go into the error handling. Which in turn sets the status to 500 and throws the InternalServerError
catch (e) {
if (e.response) {
throw InternalServerError(`${errorMessages.jwksHttpError}: [HTTP ${e.response.status}] ${JSON.stringify(e.body)}`)
}
e.statusCode = 500
throw e
}
InternalServerError does not seem fitting here as it is not unclear as to why the request can't be fulfilled as there is no private or public key available.
A more appropriate response here would be a 401
as the request itself was valid, just the token used is not authorized for this API.
When testing the same flow against the express-jwt package used in a different project it returns a 401
with the following message: UnauthorizedError: secret or public key must be provided
.
This is the behaviour I would expect from this flow as well.
Is there a chance of this being improved upon as a more appropriate response would be appreciated.