Skip to content

Conversation

andyo-tyk
Copy link
Contributor

@andyo-tyk andyo-tyk commented Oct 6, 2025

User description

Contributor checklist

  • Reviewed PR Code suggestions and updated accordingly
  • Tyklings: Labled the PR with the relevant releases
  • Tyklings: Added Jira DX PR ticket to the subject

New Contributors



PR Type

Documentation, Enhancement


Description

  • Expand JWT claim validation guidance

  • Introduce OAS multi-claim config fields

  • Rename policy/identity claim settings

  • Add classic vs OAS behavior notes


Diagram Walkthrough

flowchart LR
  Verify["JWT signature verification"] -- "on success" --> Reg["Registered claims validation (iss,aud,sub,jti,exp,iat,nbf)"]
  Reg -- "pass" --> Custom["Custom claims validation (required/exact/contains)"]
  Custom -- "pass or non-blocking" --> Authz["Authorization mapping"]
  Authz --> Policies["Apply policies (base, scope, default)"]
  Policies --> Session["Create/Update session (owner identity)"]
Loading

File Walkthrough

Relevant files
Documentation
json-web-tokens.md
Major rewrite: JWT claims validation and OAS config           

tyk-docs/content/basic-config-and-security/security/authentication-authorization/json-web-tokens.md

  • Update links and terminology for session owner extraction.
  • Add extensive sections on claim validation (registered/custom, skew).
  • Introduce new OAS fields: subjectClaims, basePolicyClaims,
    scopes.claims.
  • Add non-blocking validation, nested claims, data type handling.
  • Clarify authorization flow and policy combination best practices.
  • Add Classic vs OAS capabilities and multi-IdP guidance.
+746/-46

Copy link
Contributor

github-actions bot commented Oct 6, 2025

⚠️ Deploy preview for PR #7002 did not become live after 3 attempts.
Please check Netlify or try manually: Preview URL

Copy link
Contributor

github-actions bot commented Oct 6, 2025

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Terminology Consistency

Multiple renamed fields are introduced (e.g., policyFieldName -> basePolicyClaims, identityBaseField -> subjectClaims, scopes.claimName -> scopes.claims). Ensure all internal cross-references and earlier/later sections in the docs consistently reflect the new names and clearly mark legacy alternatives to avoid user confusion.

#### 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](https://datatracker.ietf.org/doc/html/rfc7519#section-4.3) and can be anything you want, but typically we recommend the use of `pol`. You must instruct Tyk where to look for the policy claim by configuring the `basePolicyClaims` 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:

```yaml
x-tyk-api-gateway:
  server:
    authentication:
      securitySchemes:
        jwtAuth:
          basePolicyClaims: [pol]

In the JWT, you should then provide the list of policy Ids as an array of values in that claim, for example you might declare:

  "pol": ["685a8af28c24bdac0dc21c28", "685bd90b8c24bd4b6d79443d"]

{{< note success >}}
Note

Prior to Tyk 5.10, the base policy claim was retrieved from policyFieldName; see [using multiple identity providers]({{< ref "basic-config-and-security/security/authentication-authorization/json-web-tokens#using-multiple-identity-providers" >}}) for details and for the Tyk Classic API alternative.
{{< /note >}}

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 the defaultPolicies field in the API definition, which accepts a list of policy Ids.

x-tyk-api-gateway:
  server:
    authentication:
      securitySchemes:
        jwtAuth:
          defaultPolicies:
            - 685a8af28c24bdac0dc21c28
            - 685bd90b8c24bd4b6d79443d

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 the scopes.claims to instruct Tyk where to look for the scopes and then you declare a mapping of scopes to policies within the scopes.scopeToPolicyMapping object.

x-tyk-api-gateway:
  server:
    authentication:
      securitySchemes:
        jwtAuth:
          scopes:
            scopeToPolicyMapping:
              - scope: read:users
                policyId: 685bd90b8c24bd4b6d79443d
              - scope: write:users
                policyId: 685a8af28c24bdac0dc21c28
            claims: [accessScopes]

In this example, Tyk will check the 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.

{{< note success >}}
Note

Prior to Tyk 5.10, the authorization scopes claim was retrieved from scopes.claimName; see [using multiple identity providers]({{< ref "basic-config-and-security/security/authentication-authorization/json-web-tokens#using-multiple-identity-providers" >}}) for details and for the Tyk Classic API alternative.
{{< /note >}}

Multiple scopes can be declared by setting the value of the authorization scopes 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"] }

If there is a nested key then you must use dot notation in the value configured for scopes.claims so, for the first two examples above, scopes.claims 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:

{
  "sub": "1234567890",
  "name": "Alice Smith",
  "accessScopes": ["read:users", "write:users"]
}

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:

  1. Apply direct mapped policies declared via basePolicyClaims
  2. Apply scope mapped policies declared in scopeToPolicyMapping based upon scopes in the JWT
  3. If no policies have been applied in steps 1 or 2, apply the default policies from defaultPolicies

When multiple policies are combined the following logic is applied:

  • 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


</details>

<details><summary><a href='https://github.com/TykTechnologies/tyk-docs/pull/7002/files#diff-5f5816c71b61e522b61858ca547fc6349325f0c7a4683b1c7c3a9e641b7b3f53R943-R999'><strong>Config Format Mixing</strong></a>

Some examples use YAML fenced blocks containing JSON objects (e.g., customClaimValidation snippets). This may confuse readers and tooling that copy/paste. Align fence language and structure with the shown content (YAML vs JSON) consistently across sections.
</summary>

```markdown
{
  "customClaimValidation": {
    "user.profile.department": {
      "type": "exact_match",
      "allowedValues": ["Engineering", "Sales", "Marketing"]
    },
    "user.profile.level": {
      "type": "contains",
      "allowedValues": ["senior", "lead", "principal"]
    }
  }
}

Non-blocking Validation

The non-blocking validation feature specifically enables a gradual rollout approach to validation rules by allowing you to monitor validation failures without rejecting requests.

How Non-blocking Validation Works

When configured, a validation rule can be set to "non-blocking" mode, which means:

  1. If validation passes, the request proceeds normally
  2. If validation fails, instead of rejecting the request:
  • a warning is logged in the gateway [system logs]({{< ref "api-management/logs-metrics#system-logs" >}})
  • the request is allowed to proceed to the upstream API

This allows you to:

  • Monitor how new validation rules would affect traffic without disrupting users
  • Gradually roll out stricter validation requirements
  • Debug validation issues in production environments
Configuring Non-Blocking Mode

Non-blocking mode can be configured for any custom claim validation rule with the addition of the boolean nonBlocking flag, for example:

{
  "customClaimValidation": {
    "user.profile.department": {
      "type": "exact_match",
      "allowedValues": ["Engineering", "Sales", "Marketing"]
    },
    "user.profile.level": {
      "type": "contains",
      "allowedValues": ["senior", "lead", "principal"]
    },
    "user.preferences.notifications": {
      "type": "required",
      "nonBlocking": true
    }
  }
}

The nonBlocking flag in the validation rule for user.preferences.notifications means that if this claim is missing from the received token, the token will not fail validation, but a warning will be logged.


</details>

<details><summary><a href='https://github.com/TykTechnologies/tyk-docs/pull/7002/files#diff-5f5816c71b61e522b61858ca547fc6349325f0c7a4683b1c7c3a9e641b7b3f53R1008-R1033'><strong>Accuracy of Claim Extraction Order</strong></a>

The new identity extraction order mentions `kid` first, then `subjectClaims`, then `sub`. Confirm this matches actual gateway behavior, including edge cases when `kid` is not a subject identifier in many JWTs. Consider clarifying that `kid` is only used as identity if configured/desired.
</summary>

```markdown

In order that this session can be correctly associated with the authenticated user, Tyk must extract a unique identity from the token.

The JWT specification [defines](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2) the optional `sub` claim which identifies the principal that is the subject of the JWT. In OAuth/OIDC contexts this will usually be the end user (resource owner) on whose behalf the token was issued and so is typically used to identify the session owner.

Tyk provides a flexible approach to identifying the session owner, to account for other use cases where the `sub` field is not supplied or appropriate. The identity is extracted from the token by checking the following fields in order of precedence:

1. The standard Key ID header (`kid`) in the JWT (unless the `skipKid` option is enabled)
2. The subject identity claim identified by the value(s) stored in `subjectClaims` (which allows API administrators to designate any JWT claim as the identity source (e.g., user_id, email, etc.).
3. The `sub` registered claim

{{< note success >}}
**Note**

Prior to Tyk 5.10, the subject identity claim was retrieved from `identityBaseField`; see [using multiple identity providers]({{< ref "basic-config-and-security/security/authentication-authorization/json-web-tokens#using-multiple-identity-providers" >}}) for details and for the Tyk Classic API alternative.
{{< /note >}}

When an identity has been determined, it is stored in the session object in three locations:
- in the `Alias` field
- it is used to generate a hashed session Id stored in the `keyID` field
- in the session metadata as `TykJWTSessionID`

Note that session objects can be cached to improve performance, so the identity extraction is only performed on the first request with a JWT, or when the cache is refreshed.

In this example, `skipKid` has been set to `true`, so Tyk checks the `subjectClaims` and determines that the value in the custom claim `user_id` within the JWT should be used as the identity for the session object.

Copy link
Contributor

github-actions bot commented Oct 6, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect claim reference

The sentence references audience instead of subject, which is misleading and could
confuse users configuring allowedSubjects. Replace "audience" with "subject" to
correctly describe the behavior.

tyk-docs/content/basic-config-and-security/security/authentication-authorization/json-web-tokens.md [486]

-Useful for restricting API access to specific types of subjects or known entities. If `allowedSubjects` is empty, no audience validation is performed.
+Useful for restricting API access to specific types of subjects or known entities. If `allowedSubjects` is empty, no subject validation is performed.
Suggestion importance[1-10]: 7

__

Why: The sentence incorrectly mentions "audience" when discussing allowedSubjects; changing it to "subject" fixes a clear documentation error and prevents user confusion.

Medium
General
Fix table formatting inconsistencies

The markdown table has inconsistent column separators and spacing (extra trailing
pipe/spaces) which can break rendering in some engines. Normalize the table row
formatting to ensure consistent rendering.

tyk-docs/content/basic-config-and-security/security/authentication-authorization/json-web-tokens.md [1198-1203]

 From Tyk 5.10+, Tyk OAS APIs can be configured to check multiple claim names to locate these data in the received token.
 
-| API Configuration Type | Tyk Version | Subject Identity Locator | Base Policy Locator | Scope-to-Policy Mapping Locator |
-|-------------|----------|---|---|---|
-| Tyk OAS     | pre-5.10 | `identityBaseField` | `policyFieldName` | `scopes.claimName` |
-| Tyk OAS     | 5.10+    | `subjectClaims` | `basePolicyClaims` | `scopes.claims`|  
-| Tyk Classic | all      | `jwt_identity_base_field` | `jwt_policy_field_name` | `jwt_scope_claim_name` |
+| API Configuration Type | Tyk Version | Subject Identity Locator   | Base Policy Locator   | Scope-to-Policy Mapping Locator |
+|------------------------|-------------|----------------------------|-----------------------|----------------------------------|
+| Tyk OAS                | pre-5.10    | `identityBaseField`        | `policyFieldName`     | `scopes.claimName`               |
+| Tyk OAS                | 5.10+       | `subjectClaims`            | `basePolicyClaims`    | `scopes.claims`                  |
+| Tyk Classic            | all         | `jwt_identity_base_field`  | `jwt_policy_field_name` | `jwt_scope_claim_name`         |
Suggestion importance[1-10]: 4

__

Why: Normalizing the table formatting is a minor readability/rendering improvement; content is accurate but impact is modest.

Low
Ensure correct section anchor

The intra-doc link anchor was changed to "Signature Validation" with a new header,
but the anchor used here may not resolve if the header slug differs. Update the link
to match the new "Signature Validation" section anchor to avoid a broken link.

tyk-docs/content/basic-config-and-security/security/authentication-authorization/json-web-tokens.md [387-391]

+After [verifying]({{< ref "basic-config-and-security/security/authentication-authorization/json-web-tokens#signature-validation" >}}) that the token hasn't been tampered with, Tyk processes claims in this order:
 
-
Suggestion importance[1-10]: 2

__

Why: The link already points to the correct "signature-validation" anchor added in this PR, and the improved_code is identical; minimal to no impact.

Low

Copy link

netlify bot commented Oct 6, 2025

PS. Add to the end of url /docs/nightly

Name Link
🔨 Latest commit c100f53
🔍 Latest deploy log https://app.netlify.com/projects/tyk-docs/deploys/68e3d6203bd4fc0008bd89e9
😎 Deploy Preview https://deploy-preview-7002--tyk-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

1 similar comment
Copy link

netlify bot commented Oct 6, 2025

PS. Add to the end of url /docs/nightly

Name Link
🔨 Latest commit c100f53
🔍 Latest deploy log https://app.netlify.com/projects/tyk-docs/deploys/68e3d6203bd4fc0008bd89e9
😎 Deploy Preview https://deploy-preview-7002--tyk-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

netlify bot commented Oct 6, 2025

PS. Add to the end of url /docs/nightly

Name Link
🔨 Latest commit bf3c9d6
🔍 Latest deploy log https://app.netlify.com/projects/tyk-docs/deploys/68edf098608a3a000867e885
😎 Deploy Preview https://deploy-preview-7002--tyk-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@andyo-tyk andyo-tyk requested a review from sharadregoti October 6, 2025 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants