JWT Authentication
The JWT middleware verifies that a valid JWT token is provided in the Authorization
header (Authorization: Bearer <JWT>
).
If the token can't be passed as an Authorization
header, it can be given as form data or as a query parameter.
See the tokenKey
option for more information.
With no specific configuration, a JWT middleware only validates the signature of a JWT and checks the nbf
, exp
and iat
standard claims (if they are present).
Custom claim validation can be configured with Custom Claims Validation.
Configuration Options
At least one of signingSecret
, publicKey
, jwksFile
or jwksUrl
options must be set.
signingSecret
Field | Description | Default | Required |
---|---|---|---|
signingSecret | Defines the secret used for signing the JWT certificates. It is then used by the middleware to verify incoming requests. At least one of signingSecret , publicKey , jwksFile or jwksUrl options must be set. | "" | No |
When configuring the signingSecret
, it is possible to reference a Kubernetes secret defined in the same namespace as the Middleware.
The reference to a Kubernetes secret takes the form of a URN:
urn:k8s:secret:[name]:[valueKey]
- Middleware configuration
- Kubernetes Secret
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
signingSecret: urn:k8s:secret:my-secret:signingSecret
apiVersion: v1
kind: Secret
metadata:
name: my-secret
stringData:
signingSecret: secret
signingSecretBase64Encoded
Field | Description | Default | Required |
---|---|---|---|
signingSecretBase64Encoded | Defines whether the signingSecret is base64-encoded. If set to true , the signingSecret is base64-decoded before being used. | false | No |
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
signingSecret: c3VwZXItc2VjcmV0Cg==
signingSecretBase64Encoded: true
publicKey
Field | Description | Default | Required |
---|---|---|---|
publicKey | Defines the public key used to verify secret signature in incoming requests. In that case, users should sign their token using a private key corresponding to the configured public key. At least one of signingSecret , publicKey , jwksFile or jwksUrl options must be set. | "" | No |
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
publicKey: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----
jwksFile
Field | Description | Default | Required |
---|---|---|---|
jwksFile | Defines a set of JWK to be used to verify the signature of JWTs. More information on JWK can be found in the reference documentation. The option can either be a path to a file mounted on the API Gateway or directly the content of a JWK set file. At least one of signingSecret , publicKey , jwksFile or jwksUrl options must be set. | "" | No |
If the JWT header contains a kid
header, the middleware expects to find a JWK.
If a JWK cannot be found, it returns a 401 Unauthorized
error.
- Defining the JWKS file content
- Defining the JWKS file path
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
jwksFile: |-
{
"keys": [
{
"use": "sig",
"kty": "EC",
"kid": "key-id",
"crv": "P-256",
"alg": "ES256",
"x": "EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84",
"y": "kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY"
}
]
}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
jwksFile: /etc/config/jwks.json
jwksUrl
Field | Description | Default | Required |
---|---|---|---|
jwksUrl | Defines the URL of the host serving a JWK set. More information on JWK can be found in the reference. At least one of signingSecret , publicKey , jwksFile or jwksUrl options must be set. | "" | No |
The keys are cached if the HTTP Cache Control allows for caching.
This option can either be set to a full URL (e.g.: https://www.googleapis.com/oauth2/v3/certs
) or to a path (e.g.: /oauth2/v3/certs
).
In the first case, the middleware fetches the keys located at the URL to verify the token.
In the second case, the middleware builds the full URL using the iss
property found in the JWT claims.
It does so by concatenating the host defined by iss
and the path set by jwksURL
.
If the JWT header contains a kid
header, the middleware expects to find a JWK.
If a JWK cannot be found, it returns a 401 Unauthorized
error.
If jwksUrl
is set to a path and the iss
property is missing in the JWT it's trying to verify, the middleware returns a 401 Unauthorized
error.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
jwksUrl: https://www.googleapis.com/oauth2/v3/certs
forwardAuthorization
Field | Description | Default | Required |
---|---|---|---|
forwardAuthorization | Defines whether the authorization header will be forwarded or stripped from a request after it has been approved by the middleware. | false | No |
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
forwardAuthorization: true
forwardHeaders
Field | Description | Default | Required |
---|---|---|---|
forwardHeaders | Defines the HTTP headers to add to requests and populates them with values extracted from the access token claims returned by the authorization server. | [] | No |
Claims to be forwarded that are not found in the JWT result in empty headers.
The forwardHeaders
option can only be used with JWT-formatted token.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
forwardHeaders:
Group: grp
Expires-At: exp
tokenKey
Field | Description | Default | Required |
---|---|---|---|
tokenKey | Defines the name of the query and form data parameter used for passing the JWT, for applications that can't pass it in the Authorization header. The middleware always looks in the Authorization header first, even with this option enabled. | "" | No |
This option should only be enabled if the JWT cannot be passed as an Authorization header, as it is not recommended by the RFC.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
tokenKey: access_token
claims
Field | Description | Default | Required |
---|---|---|---|
claims | Defines the claims to validate in order to authorize the request. | "" | No |
The claims
option can only be used with JWT-formatted token.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
claims: Equals(`grp`, `admin`)
Syntax
The following functions are supported in claims
:
Function | Description | Example |
---|---|---|
Equals | Validates the equality of the value in key with value . | Equals(`grp`, `admin`) |
Prefix | Validates the value in key has the prefix of value . | Prefix(`referrer`, `http://example.com\`) |
Contains (string) | Validates the value in key contains value . | Contains(`referrer`, `/foo/`) |
Contains (array) | Validates the key array contains the value . | Contains(`areas`, `home`) |
SplitContains | Validates the value in key contains the value once split by the separator. | SplitContains(`scope`, ` `, `writer`) |
OneOf | Validates the key array contains one of the values . | OneOf(`areas`, `office`, `lab`) |
All functions can be joined by boolean operands. The supported operands are:
Operand | Description | Example |
---|---|---|
&& | Compares two functions and returns true only if both evaluate to true. | Equals(`grp`, `admin`) && Equals(`active`, `true`) |
|| | Compares two functions and returns true if either evaluate to true. | Equals(`grp`, `admin`) || Equals(`active`, `true`) |
! | Returns false if the function is true, otherwise returns true. | !Equals(`grp`, `testers`) |
All examples will return true for the following data structure:
{
"active": true,
"grp": "admin",
"scope": "reader writer deploy",
"referrer": "http://example.com/foo/bar",
"areas": [
"office",
"home"
]
}
Nested Claims
Nested claims are supported by using a .
between keys. For example:
user.name
{
"active": true,
"grp": "admin",
"scope": "reader writer deploy",
"referrer": "http://example.com/foo/bar",
"areas": [
"office",
"home"
],
"user" {
"name": "John Snow",
"status": "undead"
}
}
John Snow
If the key
contains a dot, the dot can be escaped using \.
If the key
contains a \
, it needs to be doubled \\
.
usernameClaim
Field | Description | Default | Required |
---|---|---|---|
usernameClaim | Defines the claim that will be evaluated to populate the clientusername in the access logs. | "" | No |
The usernameClaim
option can only be used with JWT-formatted token.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
usernameClaim: userId
clientConfig
Defines the configuration used to connect the API Gateway to a Third Party Software such as an Identity Provider.
clientConfig.tls
The table below lists the configuration options in Traefik Hub to define a TLS connection.
Value | Description | Required |
---|---|---|
clientConfig.tls.ca | PEM-encoded certificate bundle or a URN referencing a secret containing the certificate bundle used to establish a TLS connection with the authorization server | No |
clientConfig.tls.cert | PEM-encoded certificate or a URN referencing a secret containing the certificate used to establish a TLS connection with the Vault server | No |
clientConfig.tls.key | PEM-encoded key or a URN referencing a secret containing the key used to establish a TLS connection with the Vault server. | No |
clientConfig.tls.insecureSkipVerify | Disables TLS certificate verification when communicating with the authorization server. Useful for testing purposes but strongly discouraged for production. | No |
When configuring the tls.ca
, tls.cert
, tls.key
, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware.
The reference to a Kubernetes secret takes the form of a URN:
urn:k8s:secret:[name]:[valueKey]
- Middleware configuration
- Kubernetes TLS secret
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
clientConfig:
tls:
ca: "urn:k8s:secret:tls:ca"
cert: "urn:k8s:secret:tls:cert"
key: "urn:k8s:secret:tls:key"
insecureSkipVerify: true
apiVersion: v1
kind: Secret
metadata:
name: tls
stringData:
ca: |-
-----BEGIN CERTIFICATE-----
MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
98TwDIK/39WEB/V607As+KoYazQG8drorw==
-----END CERTIFICATE-----
cert: |-
-----BEGIN CERTIFICATE-----
MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
98TwDIK/39WEB/V607As+KoYazQG8drorw==
-----END CERTIFICATE-----
key: |-
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49
AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu
KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ==
-----END EC PRIVATE KEY-----
clientConfig.timeoutSeconds
Field | Description | Default | Required |
---|---|---|---|
clientConfig.timeoutSeconds | Defines the time before giving up requests to the authorization server. | 5 | No |
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
clientConfig:
timeoutSeconds: 15
clientConfig.maxRetries
Field | Description | Default | Required |
---|---|---|---|
clientConfig.maxRetries | Defines the number of retries for requests to authorization server that fail. | 3 | No |
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
clientConfig:
maxRetries: 5
Advanced Configuration Example
Below is an advanced configuration example using custom claims validation and forward headers:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: test-jwt
spec:
plugin:
jwt:
signingSecret: my-secret
forwardHeaders:
Group: grp
Expires-At: exp
claims: Equals(`grp`, `admin`)