Multiple JWT policies
Enforce gateway- or route-based JWT authentication by using multiple policies.
For example, you might have use cases similar to the following:
- For a single virtual gateway, you have many routes. For each route, you want to enforce that only a specific JWT provider is valid.
- You want different teams to be able to add their own policies, for more self-service capabilities.
For more information about JWTs, see the JWT overview and API docs.
Before you begin
- Set up Gloo Mesh Gateway in a single cluster.
- Install Bookinfo and other sample apps.
Configure an HTTP listener on your gateway and set up basic routing for the sample apps.
Configure JWT policies
Create a JWT policy for each route that requires JWT authentication.
The following example is for a basic JWT policy that uses a local JWT issuer and inline public key. The policy does the following:
- Enables JWT authentication for the selected route.
- Configures the
https://dev.example.comissuer. - Adds the value of an
orgclaim from the JWT payload to anX-Orgheader in the request, if present. - Adds the value of an
emailclaim from the JWT payload to anX-Emailheader in the request, if present. - Checks requests by using the token found in the
X-Authheader with the prefixBearer <token>, or in a query parameterauth_token=<token>. Note that if a request has both the header and query parameter, both tokens must be valid for Gloo Gateway to accept the request.
The following example is for a basic JWT policy that uses a local JWT issuer and inline public key. The policy does the following:
- Enables JWT authentication for the selected route.
- Configures the
https://login.example.comissuer. - Adds the value of an
orgclaim from the JWT payload to anX-Orgheader in the request, if present. - Adds the value of an
emailclaim from the JWT payload to anX-Emailheader in the request, if present. - Adds the value of a
scopeclaim from the JWT payload to anX-Scopeheader in the request, if present. - Checks requests by using the token found in the
X-Authheader with the prefixBearer <token>, or in a query parameterauth_token=<token>. Note that if a request has both the header and query parameter, both tokens must be valid for Gloo Gateway to accept the request.
Review the following table to understand this configuration. For more information, see the API docs.
| Setting | Description |
|---|---|
applyToRoutes | Use labels to configure which routes to apply the policy to. This example label matches the app and route from the example route table that you apply separately. If omitted and you do not have another selector such as applyToDestinations, the policy applies to all routes in the workspace. |
phase | This example sets no priority, so the default value of zero is used. |
providers | Enter a name for the provider to help you map the provider when viewing logs to debug. The provider name does not affect the policy’s behavior and cannot be used by other resources to select the policy. |
claimsToHeaders | Optionally set the claims from the JWT payload that you want to extract and add as headers to the request before the request is forwarded to the upstream destination. This example extracts the same two org and email claims and adds them as headers for both providers. The login-example also has an additional scope claim. |
claimsToHeaders.append | Enter a boolean value to add a claim’s value if the header exists in the request. Use true to append the claim’s value to the header, and false to overwrite any existing value in the header. |
claimsToHeaders.claim | Enter the name of the claim in the JWT payload to get the value for the header. |
claimsToHeaders.header | Enter the request header that the value of the claim is copied to. |
issuer | Optionally, set the JWT issuer, usually as a subdomain of a URL or email address. If set, the iss field in the JWT token must match this field, or else the request is denied. If unset, the iss field in the JWT token is not checked. In this example, the issuer is set to a unique URL per provider, https://dev.example.com or https://login.example.com. |
keepToken | This value is set to true so that the JWT is kept in the request after verification. This way, other policies can use the JWT information as needed. |
local | Provide the PEM-formatted public key to verify the JWT token. In this example, the public key is written inline to the policy for testing purposes. For production scenarios, you can set a remote reference to your JSON Web Key Set (JWKS) server instead of this local setting. |
Try out multiple JWT policies
For quick testing, you can use sample keys with dev-example and login-example JWTs. For more details about the sample JWT, see the GitHub readme.
Apply the JWT policy with the
dev-exampleprovider for the httpbin app. For more information about this policy, see the configuration example.kubectl apply -f https://gist.githubusercontent.com/artberger/674bab05350c9a048303cc7daaffe730/raw/daf7d9b64e5e9ecf309f17123e01f5a6cbb6c7eb/jwt-policy-basic.yamlCreate another JWT policy with the
login-exampleprovider for the ratings app. For more information about this policy, see the configuration example.kubectl apply -f https://gist.githubusercontent.com/artberger/a69e3d405457ae9a3ac2ad1838937b86/raw/04de8f1042ab8d63b63e6781d1508e61163f4133/jwt-policy-basic-login.yamlSend a request to the httpbin app without any authentication. Notice that your request is denied with a
401error.Example output:curl -vik -H "X-httpbin: true" --resolve www.example.com:80:${INGRESS_GW_ADDRESS} http://www.example.com:80/getcurl -vik -H "X-httpbin: true" --resolve www.example.com:443:${INGRESS_GW_ADDRESS} https://www.example.com:443/getHTTP/1.1 401 Unauthorized www-authenticate: Bearer realm="http://www.example.com/get" ... Jwt is missingGet a sample JWT that is preconfigured to meet the validation requirements that you set in the JWT policy for the
dev-exampleprovider.TOKEN=$(curl https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/gloo-gateway/jwt/dev-example.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decodeExample output:
{"iss":"https://dev.example.com","exp":4804324736,"iat":1648651136,"org":"internal","email":"dev1@solo.io","group":"engineering","scope":"is:developer%Try the request to the httpbin app again, this time with your
dev-exampletoken. Notice that your request is now accepted!In the example output you get back acurl -vik -H "X-Auth: Bearer ${TOKEN}" -H "X-httpbin: true" --resolve www.example.com:80:${INGRESS_GW_ADDRESS} http://www.example.com:80/getcurl -vik -H "X-Auth: Bearer ${TOKEN}" -H "X-httpbin: true" --resolve www.example.com:443:${INGRESS_GW_ADDRESS} https://www.example.com:443/get200response. You also can see theX-EmailandX-Orgheaders that you appended in theclaimsToHeaderssection of the policy.HTTP/1.1 200 OK ... { "args": {}, "headers": { "Accept": "*/*", "Host": "www.example.com", "X-Email": "dev1@solo.io", "X-Envoy-Attempt-Count": "1", "X-Envoy-Decorator-Operation": "httpbin.default.svc.cluster.local:8000/*", "X-Envoy-Internal": "true", "X-Httpbin": "true", "X-Org": "internal" },Send a request to the ratings app without authentication. Notice that your request is denied with a
401error.Example output:curl -vik --resolve www.example.com:80:${INGRESS_GW_ADDRESS} http://www.example.com:80/ratings/1curl -vik --resolve www.example.com:443:${INGRESS_GW_ADDRESS} https://www.example.com:443/ratings/1HTTP/1.1 401 Unauthorized www-authenticate: Bearer realm="http://www.example.com/get" ... Jwt is missingGet another sample JWT that is preconfigured to meet the validation requirements that you set in the JWT policy for the
login-exampleprovider.TOKEN_LOGIN=$(curl https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/gloo-gateway/jwt/login-example.jwt -s) && echo "$TOKEN_LOGIN" | cut -d '.' -f2 - | base64 --decode -Example output:
{"iss":"https://login.example.com","exp":4804324736,"iat":1648651136,"org":"external","email":"user2@example.com","group":"user","scope":"is:reader%Try the request to the ratings app again, this time with your
login-exampletoken. Notice that your request is now accepted!curl -vik -H "X-Auth: Bearer ${TOKEN_LOGIN}" --resolve www.example.com:80:${INGRESS_GW_ADDRESS} http://www.example.com:80/ratings/1curl -vik -H "X-Auth: Bearer ${TOKEN_LOGIN}" --resolve www.example.com:443:${INGRESS_GW_ADDRESS} https://www.example.com:443/ratings/1In the example output you get back a
200response.HTTP/1.1 200 OK ... * Connection #0 to host www.example.com left intact {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}%
Cleanup
You can optionally remove the resources that you set up as part of this guide.kubectl -n bookinfo delete jwtpolicy jwt-policy-ratings
kubectl -n httpbin delete jwtpolicy jwt-policy