Verifying JWT with JWKS uri throws a 500

When verifying an auth token using the JWKS uri as the public key, I receive a 500 internal error:

{
    "fault": {
        "faultstring": "NullPointerException",
        "detail": {
            "errorcode": "Internal Server Error"
        }
    }
}

The auth token is coming in via the authorization header.

My VerifyJWS policy looks like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWS name="JWS-VerifyIdaToken" enabled="true">
    <DisplayName>JWS-VerifyIdaToken</DisplayName>
    <Algorithm>RS256</Algorithm>
    <PublicKey>
        <JWKS uri="https:/jwks_uri/jwks"/>
    </PublicKey>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</VerifyJWS>

My trace output for the VerifyJWS policy step clearly show it’s able to pull the required properties from the looks like:

Variables Read and Assigned

jws.JWS-VerifyIdaToken.valid

false

jws.JWS-VerifyIdaToken.header-json

jws.JWS-VerifyIdaToken.header-claim-names

[x5t, kid, typ, alg]

jws.JWS-VerifyIdaToken.decoded.header.x5t

BrfGYpn6HU1Uc6PwDue94PM3rgA

jws.JWS-VerifyIdaToken.decoded.header.kid

gou8yAJLiQVa0eoEjcl4Y2aXlsgQrKsOnyiNILUgZiQ

jws.JWS-VerifyIdaToken.decoded.header.typ

jws.JWS-VerifyIdaToken.decoded.header.alg

RS256

JWS.failed

true

Content-Type

application/json

Error Content → Body

{“fault”:{“faultstring”:“NullPointerException”,“detail”:{“errorcode”:“Internal Server Error”}}}

action

ABORT

stepDefinition-async

false

internal

false

stepDefinition-type

JWS

type

VerifyJWSStepExecution

enforcement

request

stepDefinition-continueOnError

false

stepDefinition-displayName

JWS-VerifyIdaToken

stepDefinition-name

JWS-VerifyIdaToken

stepDefinition-enabled

true

result

false

error

null

type

ErrorPoint

state

PROXY_REQ_FLOW

error.class

java.lang.NullPointerException

Identifier

fault

I’ve been able to verify the token using other online services such as https://jwt.davetonge.co.uk/

2 Likes

This is possibly a bug with where it is unable to retrieve the JWKS if passed as a URI.

Please confirm that if you pass in the JWKS as a ref (use a ServiceCallout policy to grab the JWKS before the ValidateJWS) works?

1 Like

Hi Joey,

Yes, using a service callout to fetch the jwks payload works fine.

For posterity..

My ServiceCallout policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="SC-FetchJwks">
    <DisplayName>SC-FetchJwks</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="jwksRequest">
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </Request>
    <Response>jwksResponse</Response>
    <HTTPTargetConnection>
        <Properties/>
        <URL>http://jwks_uri/jwks</URL>
    </HTTPTargetConnection>
</ServiceCallout>

My VerifyJWS policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWS name="JWS-VerifyToken">
    <DisplayName>JWS-VerifyToken</DisplayName>
    <Algorithm>RS256</Algorithm>
    <PublicKey>
        <JWKS ref="jwksResponse.content"/>
    </PublicKey>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    <KnownHeaders/>
    <IgnoreCriticalHeaders/>
</VerifyJWS>

1 Like

Thanks for the example code.
The relevant bug is b/139360107.

Just a further suggestion: it’s probably a good idea to cache the result of the SC-FetchJwks for maybe 30 minutes or so. Rather than invoking the ServiceCallout for every time you verify a token, you’d use the same JWKS data, from cache. That means the sequence would not be:

  • ServiceCallout - to fetch JWKS
  • VerifyJWT (specifying the jwksResponse.content for the JWKS data)

But instead it would be:

  • LookupCache - to see if JWKS response is present
  • ServiceCallout - conditional, to retrieve jwksResponse if cache is cold
  • PopulateCache - conditional, to set the cache
  • LookupCache - conditional, to retrieve the just cached data into a context variable
  • VerifyJWT
2 Likes

Thanks Dino. I’ll add to that ticket.

The bug seems to have been resolved. However, if I try to use a variable in the address,

<JWKS uri="https://{oam_env}/connect/jwk_uri"/>

to dynamically change the destination based on the Apigee deployment environment, still it returns a 500 error

{
    "fault": {
        "faultstring": "NullPointerException",
        "detail": {
            "errorcode": "Internal Server Error"
        }
    }
}

Am I doing something wrong or is it not allowed to use the variables in this case?

Thanks for your help.

The bug seems to have been resolved.

Glad to hear it.

Am I doing something wrong

Yes

or is it not allowed to use the variables in this case?

yes, it is not allowed.

There is a SEPARATE feature enhancement which will allow you to specify a variable that holds the URI. It won’t be a message template, but it will be a variable, like (uriref=‘variablename’). ref: b/139642475. I don’t have an estimate on availability of that feature. For now you need to use hard-coded URIs.

And also, getting a fault that says “NullPointerException” seems to also be a bug in Apigee. It shouldn’t do that. It should instead just fail to resolve the host. I think maybe you will still get a 500 error, but, it shouldn’t give you a lame message like “NullPointerException” . Thanks for reporting that. r/159341213