We’re running Tyk v5.14.0. We have an API deployed using OpenAPI. We’re trying to use JWT authentication in Tyk, but as soon as we enable it, everything starts returning { "error": "Access to this API has been disallowed" }. The Tyk logs show the following:
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Started","mw":"VersionCheck","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","ts":1791995573119053033,"type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","code":200,"level":"debug","message":"Finished","mw":"VersionCheck","ns":76530,"org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Started","mw":"RateCheckMW","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","ts":1791995573119144451,"type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","code":200,"level":"debug","message":"Finished","mw":"RateCheckMW","ns":18873,"org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Started","mw":"AuthKey","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","ts":1791995573119174132,"type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Querying local cache","mw":"AuthKey","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Querying keystore","mw":"AuthKey","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"},
{"err":"key not found","inbound-key":"****Xjfg","level":"debug","message":"Could not get session detail, key not found","prefix":"auth-mgr","time":"2026-10-14T16:32:53Z"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","level":"debug","message":"Querying authstore","mw":"AuthKey","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"},
{"err":"key not found","inbound-key":"****Xjfg","level":"debug","message":"Could not get session detail, key not found","prefix":"auth-mgr","time":"2026-10-14T16:32:53Z"},
{"api_id":"claims-api-v1","api_name":"Vyne Claims API v1","key":"****Xjfg","level":"info","message":"Attempted access with non-existent key.","mw":"AuthKey","org_id":"default","origin":"10.89.0.5","path":"/v1/claims","span_id":"167380e09c803bea","time":"2026-10-14T16:32:53Z","trace_id":"b8587e5773bbae473b5467889488e31e","type":"request"}
Tyk is running locally as a container in Podman managed using Aspire, with the following relevant configuration:
// General configuration
.WithEnvironment("TYK_GW_LOGFORMAT", "json")
.WithEnvironment("TYK_GW_LOGLEVEL", "debug")
.WithEnvironment("TYK_GW_LISTENPORT", dataPort.ToString(CultureInfo.InvariantCulture))
.WithEnvironment("TYK_GW_CONTROLAPIPORT", controlPort.ToString(CultureInfo.InvariantCulture))
.WithEnvironment("TYK_GW_SECRET", tykPassword)
.WithEnvironment("TYK_GW_APPPATH", tykAppsPath)
.WithEnvironment("TYK_GW_POLICIES_POLICYSOURCE", "file")
.WithEnvironment("TYK_GW_POLICIES_POLICYPATH", tykPoliciesPath)
// Don't use wildcard matching! If we specify a path, it had better be that path and not something vaguely similar!
.WithEnvironment("TYK_GW_HTTPSERVEROPTIONS_ENABLESTRICTROUTES", "true")
.WithEnvironment("TYK_GW_HTTPSERVEROPTIONS_ENABLEPATHPREFIXMATCHING", "true")
// 10 MiB gateway-wide body limit; partners will hard-code this once published
.WithEnvironment("TYK_GW_HTTPSERVEROPTIONS_MAXREQUESTBODYSIZE", "10485760")
// Access logs just write to the console and are not necessarily related to OpenTelemetry
.WithEnvironment("TYK_GW_ACCESSLOGS_ENABLED", "true")
.WithEnvironment("TYK_GW_HEALTHCHECK_ENABLEHEALTHCHECKS", "true")
.WithEnvironment("TYK_GW_ENABLEANALYTICS", "true")
.WithEnvironment("TYK_GW_ANALYTICSCONFIG_ENABLEDETAILEDRECORDING", "true")
.WithEnvironment("TYK_GW_SESSIONLIFETIMERESPECTSKEYEXPIRATION", "true")
.WithEnvironment("TYK_GW_HASHKEYS", "false")
.WithEnvironment("TYK_GW_HASHKEYFUNCTION", "sha256")
.WithEnvironment("TYK_GW_ENABLEHASHEDKEYSLISTING", "true")
.WithEnvironment("TYK_GW_USEREDISLOG", "true")
The OpenAPI document specifies:
"securitySchemes": {
"Bearer": {
"type": "http",
"description": "Use HTTP Bearer authentication with a JWT obtained from the Auth service.",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
Along with this relevant part of the x-tyk-api-gateway extension:
"authentication": {
"enabled": true,
"stripAuthorizationData": false,
"securitySchemes": {
"Bearer": {
"enabled": true,
"header": {
"enabled": true,
"name": "Authorization"
},
"signingMethod": "rsa",
"skipKid": false,
"subjectClaims": ["sub"],
"defaultPolicies": ["claims-api-default"],
"jwksURIs": [
{
"url": "https://test.stytch.com/v1/b2b/sessions/jwks/project-test-ca8e1a9c-cda5-4c8f-8f38-989d30d91b51"
}
],
"allowedIssuers": ["stytch.com/project-test-ca8e1a9c-cda5-4c8f-8f38-989d30d91b51"],
"allowedAudiences": ["project-test-ca8e1a9c-cda5-4c8f-8f38-989d30d91b51"],
"customClaimValidation": {
"scope": {
"type": "contains",
"allowedValues": ["claims:write"]
}
}
}
}
}
I have created the claims-api-default policy as follows:
{
"access_rights": {
"claims-api-v1": {
"api_id": "claims-api-v1",
"api_name": "Vyne Claims API v1"
}
},
"active": true,
"id": "claims-api-default",
"key_expires_in": 2592000,
"name": "Vyne Claims API default access",
"orgId": "default",
"partitions": {
"acl": true,
"rate_limit": false,
"quota": false,
"complexity": false,
"per_api": false
}
}
I don’t understand what Tyk is doing with the JWT to create or not create a session/key. The sub claim of the JWT is m2m-client-test-93ba1026-f72e-41e2-8e2e-c9239cdbc50c, but the logs show a redacted key ending in Xjfg which appears to be the final characters of the entire JWT. Changing TYK_GW_HASHKEYS didn’t make any difference. I also don’t see any sessions or other data in the Redis cache.
Do we need to change something to get Tyk to automatically create a session for JWT authentication? The documentation explicitly says:
Once validated, Tyk creates an internal session for the request (step 5).