Introduction
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting claims between parties as a JSON object. The information in the JSON object is digitally signed using either a secret (with the HMAC algorithm) or a public/private key pair (using RSA or ECDSA encryption) allowing the JWT to be used for client authentication.JWT Workflow
JWTs are commonly used in OAuth 2.0 and OpenID Connect flows to authenticate users and authorize access to APIs. The following diagram illustrates the typical flow of JWT authentication with Tyk Gateway:- Token Issuance by Identity Provider (IdP): The Identity Provider (IdP) issues a JWT with the appropriate claims. These claims represent the permissions granted by the user to the client application.
- Client as Token Bearer: The Client Application acts as the bearer of the JWT (access token). Although the client may have access to multiple APIs, the user’s delegated scopes restrict actual access. For example, a client with access to 5 APIs might only get a token allowing access to 2, depending on the user’s delegation.
- JWT Presented to Tyk Gateway: The client includes the JWT in its API requests to the Tyk Gateway as an access token.
- JWT Validation via JWK/JWKS: Tyk validates the JWT’s signature using a JSON Web Key (JWK). This key can be statically configured or dynamically fetched from the IdP via a JSON Web Key Set (JWKS) endpoint, supporting key rotation and multiple keys.
- Authorization via Claims and Policies: Claims within the JWT can be used by Tyk Gateway’s authorization process to configure rate and quota limits via Tyk’s Security Policy system. Within the API definition, JWT claims can be “mapped” onto security policies which will then be applied to the request.
- Stateless Authentication: A key advantage of JWT authentication is that Tyk does not store any user credentials or session data. It never sees the user directly - it trusts the authorization server to have authenticated the user and issued a valid token.
Key Benefits
This documentation is focused on how to use Tyk’s JWT Auth and there are many excellent sources online where you can learn more about JWTs so we won’t deep-dive into that topic, but to whet your appetite, here are some of the benefits from using JWT with Tyk:- Stateless Authentication: Eliminates the need for server-side session storage, improving scalability.
- Flexible Integration: Works with multiple identity providers including Auth0, Okta, and custom JWT issuers.
- Enhanced Security: Supports multiple signature validation methods (RSA, ECDSA, HMAC) and claim verification.
- Granular Access Control: Leverage JWT claims for policy enforcement and scope-based permissions.
- Performance Optimized: Efficient token validation with minimal overhead and support for JWKS caching.
Quick Start: Securing APIs with Auth0 or Keycloak
In this tutorial, we’ll secure a Tyk OAS API using JWT authentication with either Auth0 or Keycloak as the identity provider.If you want to try out JWT Auth without linking up to a third-party IdP then you can skip step 1 and provide the base64 encoded public key for your JWT (in the
source
field rather than configuring jwksURIs
) in step 3. You’ll need to generate a JWT for the request, but otherwise everything stays the same.Now back to the tutorial…Prerequisites
- A Tyk installation (Cloud or Self-Managed) with Tyk Dashboard license
- An Auth0 account or Keycloak installation
- An existing Tyk OAS API (see this tutorial)
- Postman, cURL, or another API testing tool
Step-by-Step Guide
-
Configure Your Identity Provider to obtain your JWKS URI
The first step is to configure your Identity Provider (IdP) to issue JWTs and provide a JWKS URI that Tyk can use to validate the tokens. Below are instructions for both Auth0 and Keycloak.
- Log in to your Auth0 dashboard
- Navigate to Applications > APIs and click Create API
- Enter a name and identifier (audience) for your API
- Note your Auth0 domain (e.g.
your-tenant.auth0.com
) - Your JWKS URI will be:
https://your-tenant.auth0.com/.well-known/jwks.json
-
Create a Security Policy
- In the Tyk Dashboard, navigate to Policies
- Click Add Policy
- Configure the policy:
- Name:
JWT Auth Policy
- APIs: Select your Tyk OAS API
- Access Rights: Configure appropriate paths and methods
- Authentication: Select JWT
- JWT Scope Claim Name: Enter the JWT claim that contains scopes (e.g.
scope
orpermissions
) - Required Scopes: Add any required scopes for access (optional)
- Name:
- Click Create to save your policy
-
Configure JWT Authentication in Tyk OAS API
- Navigate to APIs and select your API
- Click Edit
- Enable Authentication in the Server section, select JSON Web Token (JWT) as the authentication method
- Configure the JWT settings:
- Token Signing Method: Select
RSA Public Key
- Subject identity claim: Set to
sub
- JWKS Endpoint: Enter your JWKS URI for your IdP obtained in step 1
- Policy claim: Set to
pol
- Default policy: Select
JWT Auth Policy
(the policy you created previously) - Clock Skew (optional): Set to accommodate time differences (e.g.
10
) - Authentication Token Location:
header
- Header Name:
Authorization
- Strip Authorization Data:
Enabled
- Token Signing Method: Select
- Click Save API
-
Test your API
- Obtain a JWT from your IdP
- Make a request to your API providing the JWT as a Bearer token in the
Authorization
header; Tyk will validate the JWT using the JWKS that it retrieves from your JWKS URI - Observe that the request is successful
How JWT Authentication works with Tyk
This diagram outlines the flow when using JWT Auth to secure access to your API.
- Alice (the user or resource owner) authenticates with the Identity Provider (IdP) and consents to delegate specific permissions to a client application (steps 1 and 2).
- The client application receives an authorization code, which it then exchanges for an access token (step 3). This is a bearer token, meaning that the client can present it to access protected resources on behalf of the user (resource owner / Alice).
- When the client sends a request to the API gateway , it includes the access token (JWT) in the request - usually in the Authorization header as a Bearer token (step 4).
-
Tyk validates the token’s signature, using the public key(s) of the trusted issuer (IdP):
- locate the JWT in the request (header, cookie or query parameter)
- decode the JWT
- extract the
kid
(Key ID) from the token header - fetch the public keys from all configured JWKS URIs (or use locally declared static public key)
- merge all the retrieved public keys into a single list
- search this list for a public key matching the extracted
kid
- if no match is found, the validation fails, and the request is rejected
- if a matching key is found, the JWT signature is validated using the parameters in the JWK
- if signature validation fails, the request is rejected
- if the token is valid and not expired, the request is authenticated as coming from the client, and is accepted
- Next, Tyk will create an internal session for the request which will be used to control access rights, rate limits, usage quotas and in tracking logs (step 5). The session is linked to Alice using an identity that is extracted from the JWT claims.
-
In step 6 Tyk will proceed to enforce authorization by checking other claims to determine which Security Policies should be applied to the session:
- check for the value in the policy claim within the JWT (identified by the value stored in
policyFieldName
) - use this to identify the Tyk Security Policy (or policies) to be applied to the request
- if there is no direct policy mapping, then the
defaultPolicy
will be used
- if there is no direct policy mapping, then the
- apply the identified policies to the session, configuring access rights, rate limits and usage quota
- check for the value in the policy claim within the JWT (identified by the value stored in
Session Updates
When a JWT’s claims change (for example, configuring different scopes or policies), Tyk will update the session with the new policies on the next request made with the token.Missing Policies
If a policy Id is mapped to a session, but there is no policy with that Id, Tyk will fail safe and reject the request returning theHTTP 403 Forbidden
response with Key not authorized: no matching policy
. Tyk Gateway will also log the error: Policy ID found is invalid!
.
Configuring your API to use JWT authentication
The OpenAPI Specification treats JWT authentication as a variant of bearer authentication in thecomponents.securitySchemes
object using the type: http
, scheme: bearer
and bearerFormat: jwt
:
Authorization
header, but Tyk is configurable, via the Tyk Vendor Extension, to support custom header keys and credential passing via query parameter or cooke.
authentication.stripAuthorizationData
field (Tyk Classic: strip_auth_data
).
With the JWT method selected, you’ll need to configure Tyk to handle the specific configuration of JSON Web Tokens that clients will be providing. All of the JWT specific configuration is performed within the authentication.jwt object in the Tyk Vendor Extension.
Locating the JWT in the Request
The OpenAPI Specification provides asecuritySchemes
mechanism that lets you define where the JWT should be located, for example in the request header. However, in practice, different clients may supply the token in different locations, such as a query parameter.
While OAS does not support this natively, the Tyk Vendor Extension does this by allowing configuration of alternative locations in the JWT entry in server.authentication.securitySchemes
. Building on the previous example, we can add optional query and cookie locations as follows:
JWT Signatures
Method | Cryptographic Style | Secret Type | Supported Locations for Secret | Supported Algorithms |
---|---|---|---|---|
HMAC | Symmetric | Shared secret | API definition | HS256 , HS384 , HS512 |
RSA | Asymmetric | Public key | API definition, JWKS endpoint | RS256 , RS384 , RS512 , PS256 , PS384 , PS512 |
ECDSA | Asymmetric | Public key | API definition, JWKS endpoint | ES256 , ES384 , ES512 |
Secret Management
You must provide Tyk with the secret or key to be used to validate the incoming JWTs.- For the asymmetric methods (RSA and ECDSA) the public key can be stored in the API definition or Tyk can retrieve from a public JSON Web Key Sets (JWKS) endpoint (supporting dynamic rotation of keys in the JWKS)
- For symmetric encryption (HMAC), the secret is shared between the client and Tyk and so is stored within the API definition not on the public JWKS server
Locally Stored Keys and Secrets
When storing the key or secret in the API definition, it is first base64 encoded and then configured inserver.authentication.securitySchemes.<jwtAuthScheme>.source
. For improved separation of concerns and flexibility, the key/secret can be placed in an external key value store, with the appropriate reference configured in the API definition.
For example, this fragment will configure the JWT authentication middleware to use the secret located at consul://secrets/jwt-secret
to validate the signature of incoming JWTs. Note that the external KV store reference has been base64 encoded and then stored in source
:
Remotely Stored Keys (JWKS endpoint)
Prior to Tyk 5.9.0, the middleware can only validate the incoming JWT against a single JWKS endpoint. The full URI (including protocol) must be base64 encoded and configured in<jwtAuthScheme>.source
.
For example, the following fragment will configure the JWT authentication middleware to retrieve the JWKS from https://your-tenant.auth0.com/.well-known/jwks.json
when validating the signature of incoming JWTs. Note that the JWKS endpoint has been base64 encoded and then stored in source
:
<jwtAuthScheme>.jwksURIs
array. Note that these URIs are not base64 encoded in the API definition and so are human-readable. Tyk will retrieve the JSON Web Key Sets from each of these endpoints and these will be used to attempt validation of the received JWT.
For example, the following fragment will configure the JWT authentication middleware to retrieve the JWKS from both Auth0 and Keycloak when validating the signature of incoming JWTs:
jwksURIs
array are not supported by Tyk Classic APIs.If both
<jwtAuthScheme>.source
and <jwtAuthScheme>.jwksURIs
are configured, the latter will take precedence.JWT Validity and Clock Skew
JSON Web Tokens have a validity period described using three Registered Claims:IssueAt
, ExpireAt
and NotBefore
.
If, on receipt of the JWT, Tyk determines that the token is not valid then it will reject the request with the “Token is not valid yet” error.
Due to the nature of distributed systems it is expected that, despite best efforts, you can end up in a situation with clock skew between the party issuing the JWT (your IdP) and the validating party (Tyk). This might occur due to the clock on the Tyk server being behind or ahead of the clock on the Identity Provider server even with all servers synchronised from the same NTP server.
You can optionally configure a maximum permissable difference between the timestamp in the token’s validity claims and Tyk’s clock, to allow for these scenarios. Each can be independently configured or omitted from the API configuration as required. The permissable skews are configured in seconds.
- expiresAtValidationSkew allows recently expired tokens to still be considered valid. This is useful when the token issuer’s clock is slightly behind Tyk’s clock.
- issuedAtValidationSkew allows tokens that claim to be issued slightly in the future to be valid. This helps when the token issuer’s clock is slightly ahead of Tyk’s clock.
- notBeforeValidationSkew allows tokens that claim to become valid slightly in the future to be valid now. This also helps when the token issuer’s clock is ahead of Tyk’s clock.
Managing Authorization with JWT
The claims within the JSON Web Token are used to configure the Authorization for the request - i.e. which resources it can access and what limits should be applied to that access.Identifying the Originator
Tyk creates an internal session object for the request. The session is used to apply the appropriate security policies to ensure that rate limits, quotas, and access controls specific to the user are correctly applied. The session also enable tracking and analytics for the user’s API usage. In order that this session can be correctly associated with the authenticated user, Tyk must extract a unique identity from the token. Tyk follows a specific priority order when extracting identity from a JWT. If an empty identity is found, Tyk will move to the next step:- The standard Key ID header (
kid
) in the JWT (unlessskipKid
is enabled) - The subject identity claim identified by the value stored in
identityBaseField
(which allows API administrators to designate any JWT claim as the identity source (e.g., user_id, email, etc.). - The Registered claim
sub
(which is the JWT specification’s recommended claim for subject identity)
- in the
Alias
field - it is used to generate a hashed session Id stored in the
keyID
field - in the session metadata as
TykJWTSessionID
skipKid
has been set to true
, so Tyk checks the identityBaseField
and determines that the value in the custom claim user_id
within the JWT should be used as the identity for the session object.
Identifying the Tyk Policies to be applied
Security Policies are applied (or mapped) to the session object to configure authorization for the request. Policies must be registered with Tyk, such that they have been allocated a unique Tyk Policy Id. Tyk supports three different types of policy mapping, which are applied in this priority order:- Direct policy mapping
- Scope policy mapping
- Default policy mapping
Direct policies
You can optionally specify policies to be applied to the session via the policy claim in the JWT. This is a Private Claim and can be anything you want, but typically we recommend the use ofpol
. You must instruct Tyk where to look for the policy claim by configuring the policyFieldName
field in the API definition.
In this example, Tyk has been configured to check the pol
claim in the JWT to find the Policy Ids for the policies to be applied to the session object:
Default policies
You must configure one or more default policies that will be applied if no specific policies are identified in the JWT claims. These are configured using thedefaultPolicies
field in the API definition, which accepts a list of policy Ids.
Scope policies
Directly mapping policies to APIs relies upon the sharing of Tyk Policy Ids with the IdP (so that they can be included in the JWT) and may not provide the flexibility required. Tyk supports a more advanced approach where policies are applied based upon scopes declared in the JWT. This keeps separation between the IdP and Tyk-specific concepts, and supports much more flexible configuration. Within the JWT, you identify a Private Claim that will hold the authorization (or access) scopes for the API. You then provide, within that claim, a list of scopes. In your API definition, you configure thescopes.claimName
to instruct Tyk where to look for the scopes and then you declare a mapping of scopes to policies within the scopes.scopeToPolicyMapping
object.
accessScopes
claim within the incoming JWT and apply the appropriate policy if that claim contains the value read:users
or write:users
. If neither scope is declared in the claim, or the claim is missing, then the default policy will be applied.
Multiple scopes can be declared within a JWT by setting the value of the claim in any of four configurations:
- a string with space delimited list of values (by standard)
"permissions": "read:users write:users"
- an array of strings
"permissions": ["read:users", "write:users"]
- a string with space delimited list of values inside a nested key
"permissions": { "access": "read:users write:users" }
- an array of strings inside a nested key
"permissions": { "access": ["read:users", "write:users"] }
claimName
so, for the first two examples above, the claimName
should be set to permissions
whilst for the the two nested examples you would use permissions.access
.
This example of a fragment of a JWT, if provided to an API with the configuration above, will cause Tyk to apply both policies to the session object:
Combining policies
Where multiple policies are mapped to a session (for example, if several scopes are declared in the JWT claim, or if you set multiple default policies) Tyk will apply all the matching policies to the request, combining their access rights and using the most permissive rate limits and quotas. It’s important when creating those policies to ensure that they do not conflict with each other. Policies are combined as follows:- Apply direct mapped policies declared via
policyFieldName
- Apply scope mapped policies declared in
scopeToPolicyMapping
based upon scopes in the JWT - If no policies have been applied in steps 1 or 2, apply the default policies from
defaultPolicies
- access rights A user gets access to an endpoint if ANY of the applied policies grant access
- rate limits Tyk uses the most permissive values (highest quota, lowest rate limit)
- other settings The most permissive settings from any policy are applied
Policy Best Practices
When creating multiple policies that might be applied to the same JWT, we recommend using partitioned policies - policies that control specific aspects of API access rather than trying to configure everything in a single policy. For example:- Create one policy that grants read-only access to specific endpoints
- Create another policy that grants write access to different endpoints
- Create a third policy that sets specific rate limits
- Set
per_api
totrue
in each policy. This ensures that the policy’s settings only apply to the specific APIs listed in that policy, not to all APIs globally. - Avoid listing the same
API ID
in multiple policies with conflicting settings. Instead, create distinct policies with complementary settings that can be safely combined.
Using Tyk Classic APIs
As noted in the Tyk Classic API documentation, you can select JSON Web Token authentication using theuse_jwt
option. Tyk Classic APIs do not natively support multiple JWKS endpoints, though a custom authentication plugin could be used to implement this functionality.
Split Token Flow
Split Token Flow addresses a fundamental security concern with JWT tokens: when a JWT is stored on a client device (browser, mobile app, etc.), all of its contents can be easily decoded since JWTs are only base64-encoded, not encrypted. This means sensitive information in the payload is potentially exposed. The JWT consists of three parts:
- Header:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
- Payload:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJlbWFpbCI6ImhlbGxvQHdvcmxkLmNvbSJ9
- Signature:
EwIaRgq4go4R2M2z7AADywZ2ToxG4gDMoG4SQ1X3GJ0
- Separating the JWT into its three component parts: header, payload, and signature
- Storing only the signature on the client side (which by itself is meaningless)
- Keeping the header and payload securely on the server side (in Tyk)
- Reconstructing the complete JWT when needed for authentication
When to Use Split Token Flow
Consider using Split Token Flow when:- Your JWT payload contains sensitive information that shouldn’t be exposed to clients
- You want to prevent token inspection by malicious actors
- You need the flexibility of JWT while maintaining higher security
- You’re implementing systems that must meet strict security compliance requirements
How Split Token Flow Works
Here’s how the process works with Tyk Gateway:-
Token Issuance:
- A
/token
endpoint is configured on Tyk from which the client should request the access token - Tyk requests an access token from an authorization server (e.g., Keycloak) on behalf of the client
- The authorization server returns a complete JWT
- Tyk intercepts this response through a Virtual Endpoint
- Tyk splits the JWT into its components and stores the header and payload in its Redis database
- Only the signature portion is returned to the client as an “opaque” token
- A
-
Token Usage:
- The client makes API requests using only the signature as their access token
- Tyk receives the request and looks up the stored header and payload using the signature
- Tyk reconstructs the complete JWT and validates it
- If valid, Tyk forwards the request to the upstream API with the full JWT
-
Security Benefits:
- The client never possesses the complete JWT, only a meaningless signature
- Token contents cannot be inspected by client-side code or malicious actors
- Token validation still occurs using standard JWT verification
Implementing Split Token Flow
-
Create a Virtual Endpoint for Token Issuance
First, create a virtual endpoint in Tyk that will:
- Receive authentication requests from clients
- Forward these requests to your authorization server
- Split the returned JWT
- Store the header and payload in Tyk’s storage
- Return only the signature to the client
- Here’s a simplified implementation:
Note that this example includes some level of abstraction for clarity and so is not a full implementation. -
Configure Custom Pre-Auth Plugin
Next, create a custom pre-auth plugin that reconstructs the JWT before it reaches the standard Tyk JWT Auth middleware:
-
Test the Implementation
To test your Split Token Flow:
Request a token from your Tyk virtual endpoint:
You’ll receive a response with only the signature as the access token, for example:Use this token to access your JWT Auth protected API where you have configured the custom pre-auth plugin and JWT Auth: