JWT validation
The following examples show how to use the JwtValidationFilter to validate signed and encrypted JWT.
The JwtValidationFilter can access JWTs in the request, provided in a
header, query parameter, form parameter, cookie, or other way. If an upstream
filter makes the JWT available in the request’s attributes context, the
JwtValidationFilter can access the JWT through the context, for example, at
${attributes.jwtToValidate}
.
For convenience, the JWT in this example is provided by the JwtBuilderFilter, and passed to the JwtValidationFilter in a cookie.
The following figure shows the flow of information in the example:
Before you start, set up and test the example in Pass runtime data in a JWT signed with PEM then encrypted with a symmetric key.
-
Add a second route to PingGateway, replacing value of the property
secretsDir
with the directory for the PEM files:-
Linux
-
Windows
$HOME/.openig/config/routes/jwt-validate.json
%appdata%\OpenIG\config\routes\jwt-validate.json
{ "name": "jwt-validate", "condition": "${find(request.uri.path, '^/jwt-validate')}", "properties": { "secretsDir": "path/to/secrets" }, "capture": "all", "heap": [ { "name": "SystemAndEnvSecretStore", "type": "SystemAndEnvSecretStore", "config": { "mappings": [{ "secretId": "id.decrypted.key.for.signing.jwt", "format": "BASE64" }] } }, { "name": "pemPropertyFormat", "type": "PemPropertyFormat", "config": { "decryptionSecretId": "id.decrypted.key.for.signing.jwt", "secretsProvider": "SystemAndEnvSecretStore" } }, { "name": "FileSystemSecretStore-1", "type": "FileSystemSecretStore", "config": { "format": "PLAIN", "directory": "&{secretsDir}", "mappings": [{ "secretId": "id.encrypted.key.for.signing.jwt.pem", "format": "pemPropertyFormat" }, { "secretId": "symmetric.key.for.encrypting.jwt", "format": { "type": "SecretKeyPropertyFormat", "config": { "format": "BASE64", "algorithm": "AES" } } }] } } ], "handler": { "type": "Chain", "config": { "filters": [{ "type": "JwtValidationFilter", "config": { "jwt": "${request.cookies['my-jwt'][0].value}", "secretsProvider": "FileSystemSecretStore-1", "decryptionSecretId": "symmetric.key.for.encrypting.jwt", "customizer": { "type": "ScriptableJwtValidatorCustomizer", "config": { "type": "application/x-groovy", "source": [ "builder.claim('name', JsonValue::asString, isEqualTo('demo'))", "builder.claim('email', JsonValue::asString, isEqualTo('demo@example.com'));" ] } }, "failureHandler": { "type": "ScriptableHandler", "config": { "type": "application/x-groovy", "source": [ "def response = new Response(Status.FORBIDDEN)", "response.headers['Content-Type'] = 'text/html; charset=utf-8'", "def errors = contexts.jwtValidationError.violations.collect{it.description}", "def display = \"<html>Can't validate JWT:<br> ${contexts.jwtValidationError.jwt} \"", "display <<=\"<br><br>For the following errors:<br> ${errors.join(\"<br>\")}</html>\"", "response.entity=display as String", "return response" ] } } } }], "handler": { "type": "StaticResponseHandler", "config": { "status": 200, "headers": { "Content-Type": [ "text/html; charset=UTF-8" ] }, "entity": [ "<html>", " <h2>Validated JWT:</h2>", " <p>${contexts.jwtValidation.value}</p>", " <h2>JWT payload:</h2>", " <p>${contexts.jwtValidation.info}</p>", "</html>" ] } } } } }
Notice the following features of the route:
-
The route matches requests to
/jwt-validate
. -
The JwtValidationFilter takes the value of the JWT from
my-jwt
. -
The SystemAndEnvSecretStore, PemPropertyFormat, and FileSystemSecretStore objects in the heap are the same as those in the route to create the JWT. The JwtValidationFilter uses the same objects to validate the JWT.
-
The JwtBuilderFilter
customizer
requires that the JWT claims matchname:demo
andemail:demo@example.com
. -
If the JWT is validated, the StaticResponseHandler displays the validated value. Otherwise, the FailureHandler displays the reason for the failed validation.
-
-
Test the setup:
-
In your browser’s privacy or incognito mode, go to https://ig.example.com:8443/jwtbuilder-sign-then-encrypt to build a JWT.
-
Log in to AM as user
demo
, passwordCh4ng31t
. The sample application displays the signed JWT. -
Go to https://ig.example.com:8443/jwt-validate to validate the JWT. The validated JWT and its payload are displayed.
-
Test the setup again, but log in to AM as a different user, or change the email address of the demo user in AM. The JWT isn’t validated, and an error is displayed.
-