JWT

Control access or route traffic based on verified claims in a JSON web token (JWT).

This feature is available with a Gloo Mesh Gateway license only.

JSON Web Tokens (JWT) are commonly used to offload authentication and authorization code from your apps. Instead of storing user session information server-side which can lead to scalability issues, you set up a JWT issuer, such as with an external auth provider. After a user authenticates, the provider returns the response with a JWT that is stored client-side. Subsequent requests from the client include the JWT, which is faster to verify than performing the entire authentication and authorization process again.

The JWT is made up of a header, a payload of user information or “claims,” and a signature. The payload often includes additional auth information, such as usernames, access roles, or API plan details. Keep in mind that JWT data is encoded but not encrypted. As such, consider using JWT policies with no personally identifiable information (PII) or sensitive data, and only on HTTPS traffic.

With Gloo Mesh policies, you can restrict and route traffic based on information that you find in the JWT. Routing based on user identity in the JWT is more secure than unauthenticated HTTP requests from a path or header. You might use JWT policies in combination with other Gloo Mesh resources, such as the following examples:

For more information, see the following resources.

Before you begin

  1. Complete the demo setup to install Gloo Mesh, Istio, and Bookinfo in your cluster.

  2. Make sure that you installed the openssl CLI tool.

  3. Create the Gloo Mesh resources for this policy in the management and workload clusters.

    The following files are examples only for testing purposes. Your actual setup might vary. You can use the files as a reference for creating your own tests.

    1. Download the following Gloo Mesh resources:
    2. Apply the files to your management cluster.
      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-1.yml --context ${MGMT_CONTEXT}
      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-2.yml --context ${MGMT_CONTEXT}
      kubectl apply -f workspace_gloo-mesh_anything.yml --context ${MGMT_CONTEXT}
      
    1. Download the following Gloo Mesh resources:
    2. Apply the files to your workload cluster.
      kubectl apply -f route-table_bookinfo_www-example-com.yml --context ${REMOTE_CONTEXT1}
      kubectl apply -f virtual-gateway_bookinfo_north-south-gw.yml --context ${REMOTE_CONTEXT1}
      kubectl apply -f workspace-settings_bookinfo_anything.yml --context ${REMOTE_CONTEXT1}
      
  4. Send a request to verify that you can reach the ratings app. If not, try Debugging your route.

    curl -vik --resolve www.example.com:443:${INGRESS_GW_IP} https://www.example.com:443/ratings/1
    

    Example output:

    HTTP/1.1 200 OK
    ...
    {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}
    

Configure JWT policies

You can apply an JWT policy at the route level. For more information, see Applying policies.

The following example is for a basic JWT policy with a local JWT issuer and inline public key. The policy does the following:

apiVersion: security.policy.gloo.solo.io/v2
kind: JWTPolicy
metadata:
  name: jwt-policy-2
  namespace: bookinfo
spec:
  applyToRoutes:
  - route:
      labels:
        route: ratings
  config:
    phase:
      preAuthz: {}
    providers:
      provider1:
        claimsToHeaders:
        - append: true
          claim: org
          header: x-org
        issuer: https://localhost
        local:
          inline: |-
            -----BEGIN RSA PUBLIC KEY-----
            MIIBCgKCAQEAyTnCHqv2VYNyDUkeFXM6guSjDBH6op1WTAgMIY57vbjrXxbgi63g
            MdxNww5kf0xeIQYg3maNfghY66x9HQrbocs/UEv/mk76mHURztIywJK+tTTx0jN9
            8TH8O2s2xHKbqL/rIM1gEtvxZtV5DOD+bTHF/UONDxlE/w3xwTZOmCDquTKauEWk
            Xcb2/Bt1jGK9GMOnopynQcXnomy9bsESrUA1qlBi0CYXuMPxxn8iVh4a4cDwVrl/
            ztR0Lce4RAWJO5q27ZB0OKCBdQTtCtRFiIv8tSHN8wTf987ykotMIwSaExLvTZ1b
            lZ7q8UmMODESVaV1SBWvAvbF99CgaT/D9QIDAQAB
            -----END RSA PUBLIC KEY-----
        tokenSource:
          headers:
          - name: X-Auth
            prefix: 'Bearer '
          queryParams:
          - auth_token

Review the following table to understand this configuration. For more information, see the API docs.

Setting Description
applyToRoutes Configure which routes to apply the policy to, by using labels. The label matches the app and the route from the route table. If omitted, the policy applies to all routes in the workspace.
phase Set when to apply the JWT filter in the request chain, either before (preAuthz) or after (postAuthz) authorization. You can also set the priority if you have multiple policies in the same phase. The lowest numbered priority is run first. In this example, the priority is left to the default value of zero.
providers Set up the JWT providers for the policy. You can name the providers to help you map the provider when viewing logs to debug. However, the provider name does not affect the policy's behavior and cannot be used by other resources to select the policy. In this example, only one provider is set up, with the name provider1.
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 one claim and adds it as a header.
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.
claim Enter the name of the claim in the JWT payload to get the value for the header. In this example, the claim is org.
header Enter the request header that the value of the claim is copied to. In this example, the header is x-org.
issuer Optionally, set the JWT issuer, usually as 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 the local host for testing purposes, https://localhost.
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.
tokenSource Specify where Gloo Mesh Gateway looks for the token to use for JWT authentication. If unset, the default locations are tried in the following order:
  1. The authorization header X-Auth with the value Bearer <token>.
  2. The query parameter for access_token, such as https://<path>?access_token=<token>.
You can set up multiple JWT tokens to verify per request. If a request has multiple header and query paramaters, all tokens must be valid for Gloo Mesh Gateway to accept the request.
headers Specify the header to get the JWT from. By default, Gloo Mesh Gateway uses the authorization header X-Auth and expects a value with a prefix of Bearer <token>. In this example, the header and prefix are explicitly set to the default values, X-Auth and 'Bearer '.
queryParameters Specify a query parameter to get the token from. The default value is access_token. This example uses a different query paramater, auth_token.

Verify JWT policies

  1. Download the example JWT policy for the ratings route that you reviewed in the previous section.

  2. Apply the example JWT policy.

    kubectl apply --context ${REMOTE_CONTEXT1} -f jwt-policy_bookinfo_jwt-policy-2.yml
    
  3. Try the request to the ratings app again. Notice that your request is now denied with a 401 error.

    curl -vik --resolve www.example.com:443:${INGRESS_GW_IP} https://www.example.com:443/ratings/1
    

    Example output:

    HTTP/2 401 
    < www-authenticate: Bearer realm="https://www.example.com/ratings/1"
    ...
    Jwt is missing* Closing connection 0
    
  4. Create a private-public key pair by using OpenSSL. You use this pair to create your own JWT token.

    1. Create a private key to sign the JWT.
      openssl genrsa 2048 > private-key.pem
      
    2. Extract the public key from the private key.
      openssl rsa -in private-key.pem -pubout
      
    3. Open the downloaded JWT policy. In the inline section, copy in the public key value from the output of the previous step, including the BEGIN/END parts. Make sure the indentation is kept.
    4. Update the JWT policy with your new public key value, which is used to verify the JWT token in subsequent requests.
      kubectl apply --context ${REMOTE_CONTEXT1} -f jwt-policy_bookinfo_jwt-policy-2.yml
      
  5. Create a JWT that uses your private key.

    1. In your browser, go to https://jwt.io/. For the subsequent steps, you can refer to the following image.
    2. From the Algorithm dropdown, select RS256.
    3. From the Decoded section, scroll to the Payload: Data pane. Replace the content by pasting the following JWT payload information.
      {
        "iss": "https://localhost",
        "exp": 4804324736,
        "iat": 1648651136,
        "org":"solo-io"
      }
      
    4. From the Decoded section, scroll to the Verify Signature pane. In the first input box for -----BEGIN PUBLIC KEY-----, replace the content by pasting the value of your public key from the previous output of your terminal.
    5. In your terminal, copy the contents of your private key.
      pbcopy > private-key.pem
      
    6. Return to your browser in the Decoded section, Verify Signature pane. In the second input box for -----BEGIN PRIVATE KEY-----, replace the content by pasting the value of your private key.
    7. From the Encoded section, copy the token value to your clipboard, such as eyJhbG..... Then in your terminal, you can manually enter pbpaste > token.jwt to create a JWT token file. This file now contains your JWT token.
    8. Optional: Click Share JWT to get your JWT information to refer to later. JWT token
  6. Try the request to the ratings app again, this time with your JWT token. Notice that your request is now accepted!

    curl -vik --resolve www.example.com:443:${INGRESS_GW_IP} "https://www.example.com:443/ratings/1?auth_token=$(cat token.jwt)"
    

    Example output:

    HTTP/2 200 
    ...
    {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}