Skip to main content

jwt-auth

Authenticates consumers with a JSON Web Token they present.

Category AuthenticationAdd it to Route, Service, Global rule, Plugin configEngine plugin jwt-authPriority 2510Needs a Consumer with a jwt-auth Credential

What it does​

jwt-auth admits a request that carries a JSON Web Token signed for one of your consumers. The consumer holds a jwt-auth credential: a Key the token names in its key claim, and either a Secret for the HS algorithms or a Public key for the others. The tokens are signed outside the gateway, and the plugin on the route reads them from the Authorization header after Bearer, or from the query parameter or the cookie the form names when the header is absent.

A token whose signature the credential checks passes as that consumer and reaches the backend. A request without a token is answered 401 with Missing JWT token in request, and a token that fails the check 401 with failed to verify jwt. Authentication shows how consumers and credentials fit together.

When to use it​

  • The sign-in service of mobile-app issues tokens signed with a shared secret, and every call the app makes carries one.
  • A partner signs its tokens with its own private key and gives you only the public key, as partner-portal does.
  • Tokens that must stop working after a while: each token carries exp, and Claims to verify refuses the ones that carry none.
  • A backend that should never see the token: Hide credentials keeps the Authorization header from it.

Not for tokens issued by an OpenID Connect identity provider — see openid-connect (Authenticates users against an OpenID Connect provider), a fixed API key a client sends as it is — see key-auth (Authenticates consumers with an API key sent in a header or query parameter) or a signature over each request instead of a token — see hmac-auth (Authenticates requests signed with an HMAC key pair).

Guides​

Pages that walk through a job with jwt-auth, step by step.

  • Accept signed tokensPut jwt-auth on a route and give the client the credential that checks the tokens it signs.

Set it up​

Refuse tokens without an expiry and keep the token out of the upstream request​

Under Basics fill Claims to verify as in the JSON below and turn on Hide credentials. Under Behavior leave Header at authorization.

The console's Add plugin panel, filled with this example.
jwt-auth · as the console saves it
{
"claims_to_verify": [
"exp"
],
"header": "authorization",
"hide_credentials": true
}

What you will see​

  • A request whose Authorization header carries a token mobile-app signed with its secret, not yet expired, is answered 200; the token is removed before the request reaches the backend, which receives X-Consumer-Username: mobile-app instead.
  • A token signed with the right secret but without an expiry claim is answered 401 with failed to verify jwt.
  • A token whose expiry has passed is answered 401 with failed to verify jwt.
  • A request without a token is answered 401 with Missing JWT token in request.

More scenarios​

Give a consumer a key and the public key that checks the tokens it signscredential

Under Credential set Key to partner-portal, set Algorithm to RS256 and set Public key to -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0q8KUqx3QiPmNjsS4fv3 DUNTYCE1RU18lC4v8VG0YZxSTX2qVk2aEUh/Pe5EvLsGRhNEujmIGdw2RbaJjJVf 9EVPYCrTc8PZnrWP0P1XHHkcMdOdln6Ph1IUOcdNeLemVSnJH7i6y3MKhrxfDYDp FFC0USTd5UBvmVkZZ1bjx4g397jYb730jbtrFLNK1rmb+sNq0ttqtpltWHxN81Vh 05AC6Pn0u8wo5Q4Y6RKZTAyA+envySlvXC2pjQUK1d4nh1FRxbPvRBMB1cu3VJIi psq8yiiGKRIb9sZ/80pWCBY8PWsVfGlMl+bbuTxZ/kq6UG63+0trpQl2EUXBNnEk BQIDAQAB -----END PUBLIC KEY----- .

jwt-auth credential · as the console saves it
{
"key": "partner-portal",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0q8KUqx3QiPmNjsS4fv3\nDUNTYCE1RU18lC4v8VG0YZxSTX2qVk2aEUh/Pe5EvLsGRhNEujmIGdw2RbaJjJVf\n9EVPYCrTc8PZnrWP0P1XHHkcMdOdln6Ph1IUOcdNeLemVSnJH7i6y3MKhrxfDYDp\nFFC0USTd5UBvmVkZZ1bjx4g397jYb730jbtrFLNK1rmb+sNq0ttqtpltWHxN81Vh\n05AC6Pn0u8wo5Q4Y6RKZTAyA+envySlvXC2pjQUK1d4nh1FRxbPvRBMB1cu3VJIi\npsq8yiiGKRIb9sZ/80pWCBY8PWsVfGlMl+bbuTxZ/kq6UG63+0trpQl2EUXBNnEk\nBQIDAQAB\n-----END PUBLIC KEY-----\n"
}

What you will see​

  • A request whose token is signed with the private key that matches the public key, and names the key, is answered 200, and the backend receives the consumer's name in X-Consumer-Username.
  • A request without a token is answered 401 with Missing JWT token in request.
Give a consumer a key and a shared secret for tokens it signs itselfcredential

Under Credential set Key to mobile-app, leave Algorithm at HS256, set Secret to <secret> and set Grace period to 30 seconds.

jwt-auth credential · as the console saves it
{
"key": "mobile-app",
"algorithm": "HS256",
"secret": "<secret>",
"lifetime_grace_period": 30
}

What you will see​

  • A request whose token is signed with the shared secret and names the key is answered 200, and the backend receives the consumer's name in X-Consumer-Username.
  • A request without a token is answered 401 with Missing JWT token in request.

Things to know​

  • Claims to verify — With exp ticked, a token without an exp claim is answered 401, and so is a token whose exp has passed.
  • Claims to verify — Ticking a claim makes it required. An exp or nbf that a token carries is checked whether it is ticked or not.
  • Claims to verify — Only exp and nbf can be ticked; iat is refused when you save.
  • Hide credentials — On, the Authorization header that carried the token does not reach the backend.
  • Secret — A credential with HS256 and no secret is refused when you save.
  • Public key — The client keeps the private key and signs its tokens with it. The credential holds only this public half, and a token it checks with RS256 passes.
  • Public key — A credential with RS256 and no public key is refused when you save.
  • Anonymous consumer — It takes a consumer's username: letters, digits, _ and -. A name with a dot in it is refused when you save.
  • Anonymous consumer — While this names an existing consumer, a request with no credential or a wrong one passes as that consumer instead of being refused. A name that belongs to no consumer refuses them with 401.
  • Your backend receives the consumer's username in X-Consumer-Username, the name of the consumer whose credential checked the token.
  • AdviceGive every token an expiry and tick exp, so that a token that leaks stops working on its own.

Settings​

The fields as the console shows them, section by section. A field under “When … is …” is there only while that value is set.

Basics​

Claims to verifyclaims_to_verifyarray of strings

Claims every token must carry, such as exp, where a token without a ticked claim is refused. An exp or nbf that a token carries is checked either way.

one of exp, nbf
Hide credentialshide_credentialsbooleandefault false

Behavior​

Headerheaderstringdefault authorization
Queryquerystringdefault jwt
Cookiecookiestringdefault jwt
Anonymous consumeranonymous_consumerstring
at least 1 character · letters, digits, hyphens and underscores up to 256 characters, or a $secret:// or $env:// reference
pattern^([$]secret://.+|[$][Ee][Nn][Vv]://.+|[a-zA-Z0-9_-]{1,256})$

Advanced​

Key claim namekey_claim_namestringdefault key
at least 1 character
Realmrealmstringdefault jwt
1 to 128 characters ·
pattern^[ -!#-[\]-~]+$
Store in contextstore_in_ctxbooleandefault false

Credential​

What each consumer's credential for jwt-auth carries.

Credential​

6 fields from the plugin's credential schema.

KeykeystringRequired

The key claim the token carries.

at least 1 character
Algorithmalgorithmstringdefault HS256
one of ES256, ES384, ES512, EdDSA, HS256, HS384, HS512, PS256, PS384, PS512, RS256, RS384, RS512

When Algorithm is ES256 or ES384 or ES512 or EdDSA or PS256 or PS384 or PS512 or RS256 or RS384 or RS512​

Public keypublic_keystringRequired

PEM. Required for the RS, ES, PS and EdDSA algorithms.

at least 1 character
When Algorithm is HS256 or HS384 or HS512· 1 field
SecretsecretstringRequired

The shared secret for the HS algorithms, the default, while RS, ES, PS and EdDSA use Public key instead. Stored on the engine and shown only to roles that manage this object.

at least 1 character
Base64 secretbase64_secretbooleandefault false

On, the secret above is read as base64.

Grace periodlifetime_grace_periodintegerdefault 0
at least 0 · in seconds

Every plugin also has Enabled, Priority, Filter, Error response and Pre-function: see Plugin execution settings.

G8 dev · Apache APISIX® 3.19.0
Apache, Apache APISIX and APISIX are trademarks of The Apache Software Foundation.