This section explains how to configure JWT validation through Avi Load Balancer using the UI and the CLI.

Avi Load Balancer supports the following JWT validation methods:

  • ​Manual upload of the JWKS keys

  • JWT Validation using JWKS keys

  • Claim-based validation using authorization rules under SSO Policy

  • Revocation using the authorization policies

JWT Validation Workflow

Communication between a client, an authorization server, and Avi Load Balancer during the JWT validation is as explained below:

  1. The client sends an unauthenticated request to the authorization server.

  2. The authorization server performs the authentication and issues a JSON web-based tokens.

  3. The client sends a request to Avi Load Balancer virtual service to access the protected resource. The client request has JWT either in the URL query or against the authorisation header.

  4. Avi Load Balancer validates the JWT in JWKS format using the public key of authorisation server that issued the JWT . If JWT is validated, NSX Advanced Load Balancer and provides access to the requested resource.

Configuring JWT Validation using the UI

To configure JWT validation through the Avi Load Balancer UI, follow the steps below:

  1. Create a JWT Server Profile.

  2. Associate the JWT Server Profile with the Authentication Profile.

  3. Create the SSO Policy.

  4. Configure the virtual service.

Creating a JWT Server Profile

To create a JWT Server Profile,
  1. Navigate to Templates > Security > JWT Server Profile.

  2. Click CREATE.

  3. Enter the Name of the Profile.

  4. Specify the unique name of the token Issuer. This is applicable only for CLIENT_AUTH profile type.

  5. Either paste the JWKS key set in the text box provided or click Import File to upload.

  6. Click Save.

Associating the JWT Server Profile with the Authentication Profile

  1. Navigate to Templates > Auth Profile > JWT Server Profile.

  2. Click CREATE.

  3. Enter the NAME of the Authentication Profile.

  4. Select the Type as JWT Validation.

  5. From the dropdown menu, select the JWT Server Profile that was created.

  6. Click Save.

Creating the SSO Policy

To create the SSO Policy,

  1. Navigate to Templates > Security > SSO Policy.

  2. Click Create.

  3. Enter the Name of the SSO Policy.

  4. Select JWT as the Type of SSO Policy.

  5. Select the JWT Auth Profile to use for validating users.

  6. Under Authentication Rules, click Add and configure the Authentication Rules as required.

  7. Under Authorization Rules, click Add and configure the Authorization Rules as required.

  8. Click Save.

Configuring the Virtual service

Associate the SSO Policy and the JWT service configuration to the virtual service.

  1. Navigate to Applications > Virtual Services.

  2. Click on CREAT VIRTUAL SERVICE.

  3. Select Advanced Setup.

  4. Configure Step 1: Settings as required and click Next.

  5. Under Step 2: Policies, click Access.

  6. Under the Access tab,

    1. Select JWT as the Access Policy.

    2. Select the SSO Policy created with the JWT Profile to be associated wih this virtual service.

    3. Specify the SSO Audience that uniquely identifies the resource server.

    4. Select the Token Location to define whether to look for the JWT in the Authorization Header or URL Query.



    5. Configure the other details for teh virtual service and click Save.

Configuring JWT Validation using CLI

To configure the JWT Validation using CLI, run the following commands:

  • Creating a JWT server profile : Login to Avi Load Balancer CLI and use the configure jwtserverprofile <profile name> command to provide values for various attributes.

    [admin:controller]: > configure jwtserverprofile jwtserver1
    [admin:controller]: jwtserverprofile> issuer https://accounts.google.com
    [admin:controller]: jwtserverprofile> jwks_keys "{"keys": [{"use": "sig", "e": "AQAB", "kty": "RSA", "alg": "RS256", "n":"sUAjG7PjTm7FkhfTUZlpiMDZb9t6Ge6rjtx0RZh5vrk8ONmEqgzmi_b6WZ-rkIfF54MZfyWiISPp9QgJBoKq9lDmFGz3zlMxu6M18TJmMj39HzRzvwDKg2ll1b-447cNXgw5wPiVl0O4Ej9qccOwl7dHzHAiJ88CZ1oOSplkJOqF71M2l_0pGH25GNZA5quW9FaATRE_Unm3C_Jb_76QjslOohF7x-cOl7mcI-TNJs29_rqJeC3pJaPUr_qRl5cc-1ALQP_rVW9m47IY0GnGbUZ6VsYefAPnvswXx21-S4nOU-Nt4EhbcMf6cZ5X6q4qWFtG6wil2hTB4lfHA_olMw", "kid":"example"}]}"
    [admin:controller]: jwtserverprofile>
    [admin:controller]: jwtserverprofile> save
    +------------+----------------------------------------------------+
    | Field             | Value                                                                                                                                                                            
    +------------+-----------------------------------------------------+
    | uuid              | jwtserverprofile-e1c8f0c2-b38c-41f4-bf1e-0f55e282797e                                                                               
    | name            | jwtserver1                                                                                                                                                                   
    | jwks_keys    | {"keys": [{"use": "sig", "e": "AQAB", "kty": "RSA", "alg": "RS256", "n":"sUAjG7P                                               
                       | jTm7FkhfTUZlpiMDZb9t6Ge6rjtx0RZh5vrk8ONmEqgzmi_b6WZ-rkIfF54MZfyWiISPp9QgJBoKq9lD          |
    |                      | mFGz3zlMxu6M18TJmMj39HzRzvwDKg2ll1b-447cNXgw5wPiVl0O4Ej9qccOwl7dHzHAiJ88CZ1oOSpl     |
    |                      | kJOqF71M2l_0pGH25GNZA5quW9FaATRE_Unm3C_Jb_76QjslOohF7x-cOl7mcI-TNJs29_rqJeC3pJaP       |
    |                      | Ur_qRl5cc-1ALQP_rVW9m47IY0GnGbUZ6VsYefAPnvswXx21-S4nOU-Nt4EhbcMf6cZ5X6q4qWFtG6wi    |
    |                      | l2hTB4lfHA_olMw", "kid":"example"}]}                                                                                                                    
    | issuer           | https://accounts.google.com                                                                                                                                   
    | tenant_ref    | admin                                                                                                                                                                          
    +------------+---------------------------------------------------+
    [admin:controller]: >
  • Associate the JWT server profile created in the previous step to the authentication profile:

    [admin:controller]: > configure authprofile authprofile1
    [admin:controller]: authprofile> jwt_profile_ref jwtserver1
    [admin:controller]: authprofile> type auth_profile_jwt
    [admin:controller]: authprofile> save
    +-----------------+-----------------------------------------------+
    | Field           | Value                                            
    +-----------------+------------------------------------------------+
    | uuid            | authprofile-e1b763d6-bbd0-4a70-9a9b-95ab60e72e11 
    | name            | authprofile1                                     
    | type            | AUTH_PROFILE_JWT                                 
    | jwt_profile_ref | jwtserver1                                       
    | tenant_ref      | admin                                            
    +-----------------+------------------------------------------------+
    [admin:controller]: >
  • Create an SSO policy using the configure ssopolicy <sso policy name> command. Associate this SSO policy with the authentication policy created in the previous step and set the type for the authentication policy as sso_type_jwt.

    [admin:controller]: > configure ssopolicy ssopolicy1
    [admin:controller]: ssopolicy> authentication_policy default_auth_profile_ref authprofile1
    [admin:controller]: ssopolicy:authentication_policy> save
    [admin:controller]: ssopolicy> type sso_type_jwt
    [admin:controller]: ssopolicy>save
    
    +----------------------------+------------------------------+
    | Field                       | Value                       |
    +----------------------------+------------------------------+
    | name                        | ssopolicy1                  |
    | authentication_policy       |                             |
    |   default_auth_profile_ref  | authprofile1                |
    | type                        | SSO_TYPE_JWT                |  
    +----------------------------+-----------------------------+
  • Associate the SSO Policy and the JWT virtual service configuration to the virtual service.Set the value of jwt_location as jwt_location_authorization_header, if the JWT is sent as Bearer Token in the authorization header.

    [admin:controller]: > configure virtualservice virtualservice1
    [admin:controller]: virtualservice> [admin:Charitha-controller]: virtualservice> sso_policy
    sso_policy                           (submode)
    sso_policy_ref                       The SSO Policy attached to the virtualservice.
    [admin:controller]: virtualservice> sso_policy_ref
    
    WORD     The SSO Policy attached to the virtualservice.
    [admin:controller]: virtualservice> sso_policy_ref  ssopolicy1
    [admin:controller]: virtualservice> jwt_config
    audience       Uniquely identifies a resource server. This is used to validate against the aud claim.
    jwt_location   Defines where to look for JWT in the request.
    jwt_name       Name by which the JWT can be identified if the token is sent as a query param in the request url.
    [admin:controller]: virtualservice> jwt_config audience
    
    WORD     Uniquely identifies a resource server. This is used to validate against the aud claim.
    [admin:controller]: virtualservice> jwt_config audience dfsrX789jsbfheDHUW2838nfewsjdf
    
    [admin:controller]: virtualservice:jwt_config> jwt_location jwt_location_
    jwt_location_authorization_header   JWT sent in the authorizarion header of the request as a bearer token.
    jwt_location_query_param            JWT sent in the request query params.
    [admin:controller]: virtualservice:jwt_config> jwt_location jwt_location_authorization_header
    [admin:controller]: virtualservice:jwt_config> save
  • Select jwt_location_query_params as the value for jwt_location, if the JWT is sent in the URL as a query parameter.

    [admin:controller]: > configure virtualservice virtualservice1
    
      [admin:controller]: virtualservice> [admin:Charitha-controller]: virtualservice> sso_policy
      sso_policy                           (submode)
      sso_policy_ref                       The SSO Policy attached to the virtualservice.
      [admin:controller]: virtualservice> sso_policy_ref
    
      WORD     The SSO Policy attached to the virtualservice.
      [admin:controller]: virtualservice> sso_policy_ref  ssopolicy1
    
      [admin:controller]: virtualservice> jwt_config
      audience       Uniquely identifies a resource server. This is used to validate against the aud claim.
      jwt_location   Defines where to look for JWT in the request.
      jwt_name       Name by which the JWT can be identified if the token is sent as a query param in the request url.
      [admin:controller]: virtualservice> jwt_config audience
    
      WORD     Uniquely identifies a resource server. This is used to validate against the aud claim.
      [admin:controller]: virtualservice> jwt_config audience dfsrX789jsbfheDHUW2838nfewsjdf
    
      [admin:controller]: virtualservice:jwt_config> jwt_location jwt_location_query_params
      [admin:controller]: virtualservice:jwt_config> jwt_location jwt_location_query_param jwt_name "jwt_token"
      [admin:controller]: virtualservice:jwt_config> save

Adding Authentication Policies

Use the authentication policy option under the configure ssopolicy <sso policy name> mode to add authentication policies to enable JWT authentication only for paths /login and /default.

[admin:controller]: > configure ssopolicy ssopolicy-3
[admin:controller]: ssopolicy>
[admin:controller]: ssopolicy> type sso_type_jwt
[admin:controller]: ssopolicy> authentication_policy
[admin:controller]: ssopolicy:authentication_policy> default_auth_profile_ref authprofile-1
[admin:controller]: ssopolicy:authentication_policy> authn_rules
New object being created
[admin:controller]: ssopolicy:authentication_policy:authn_rules> action type skip_authentication
[admin:controller]: ssopolicy:authentication_policy:authn_rules:action> save
[admin:controller]: ssopolicy:authentication_policy:authn_rules> index 1
[admin:controller]: ssopolicy:authentication_policy:authn_rules> name rule1
[admin:controller]: ssopolicy:authentication_policy:authn_rules> match
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match> path
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match:path> match_str "login"
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match:path> match_str "default"
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match:path> match_criteria does_not_equal
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match:path> save
[admin:controller]: ssopolicy:authentication_policy:authn_rules:match> save
[admin:controller]: ssopolicy:authentication_policy:authn_rules> save
[admin:controller]: ssopolicy:authentication_policy> save
[admin:controller]: ssopolicy> save
+----------------------------+-----------------------------------------+
| Field                      | Value                                          
+----------------------------+------------------------------------------+
| uuid                       | ssopolicy-6d831f8d-4ccf-43f9-af73-aa9aae8beae4 |
| name                       | ssopolicy-3                                    
| authentication_policy      |                                                
|   default_auth_profile_ref | authprofile-1                                  
|   authn_rules[1]           |                                                
|     name                   | rule1                                          
|     index                  | 1                                              
|     enable                 | True                                           
|     match                  |                                                
|       path                 |                                                
|         match_criteria     | DOES_NOT_EQUAL                                 
|         match_case         | INSENSITIVE                                    
|         match_str[1]       | login                                          
|         match_str[2]       | default                                        
|     action                 |                                                
|       type                 | SKIP_AUTHENTICATION                            
| type                       | SSO_TYPE_JWT                                   
| tenant_ref                 | admin                                          
+----------------------------+-----------------------------------------+

Adding Authorization Policies

Use the authorization policy option under the configure ssopolicy <sso policy name> mode to enable authorization with access token match.

[admin:controller]: > configure ssopolicy ssopolicy-3
[admin:controller]: ssopolicy> authorization_policy
[admin:controller]: ssopolicy:authorization_policy> authz_rules index 1 name rule1
[admin:controller]: ssopolicy:authorization_policy:authz_rules> action status_code http_response_status_code_403 type http_local_response
[admin:controller]: ssopolicy:authorization_policy:authz_rules:action> save
[admin:controller]: ssopolicy:authorization_policy:authz_rules> match
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match> access_token
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token> matches
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token:matches> type jwt_claim_type_string
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token:matches> string_match match_str "AT-dsjfndjfndsj1234-jnfdjk"
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token:matches:string_match> match_criteria equals
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token:matches:string_match> save
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token:matches> save
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match:access_token> save
[admin:controller]: ssopolicy:authorization_policy:authz_rules:match> save
[admin:controller]: ssopolicy:authorization_policy:authz_rules> save
[admin:controller]: ssopolicy:authorization_policy> save
[admin:controller]: ssopolicy> save
+----------------------------+-----------------------------------------+
| Field                      | Value                                          
+----------------------------+------------------------------------------+
| uuid                       | ssopolicy-6d831f8d-4ccf-43f9-af73-aa9aae8beae4 |
| name                       | ssopolicy-3                                    
| authentication_policy      |                                                
|   default_auth_profile_ref | authprofile-1                                  
|   authn_rules[1]           |                                                
|     name                   | rule1                                          
|     index                  | 1                                              
|     enable                 | True                                           
|     match                  |                                                
|       path                 |                                                
|         match_criteria     | DOES_NOT_EQUAL                                 
|         match_case         | INSENSITIVE                                    
|         match_str[1]       | login                                          
|         match_str[2]       | default                                        
|     action                 |                                                
|       type                 | SKIP_AUTHENTICATION                            
| authorization_policy       |                                                
|   authz_rules[1]           |                                                
|     match                  |                                                
|       access_token         |                                                
|         matches[1]         |                                                
|           is_mandatory     | True                                           
|           validate         | True                                           
|           type             | JWT_CLAIM_TYPE_STRING                          
|           string_match     |                                                
|             match_criteria | EQUALS                                         
|             match_str[1]   | AT-dsjfndjfndsj1234-jnfdjk                     
|     action                 |                                                
|       type                 | HTTP_LOCAL_RESPONSE                            
|       status_code          | HTTP_RESPONSE_STATUS_CODE_403                  
| type                       | SSO_TYPE_JWT                                   
| tenant_ref                 | admin                                          
+----------------------------+------------------------------------------+

Revocation of JWT

JWTs are designed to be portable, decoupled identities. Once authentication is performed against an authorization server and a JWT is recieved, the JWT token’s re-validation is not required. They can not be revoked at the level of the authorization server.

Avi Load Balancer uses the following methods to revoke a JWT:

  • Configure the access tokens (JWTs) to be short-lived. As the JWT gets expired, the client will be forced to re-authenticate or to use a refresh token to request for the new JWT.

  • Maintain a list of the revoked token in a string group with jti as the key, one for each authorization server.

  • Use the SSO policy to configure authorization rules based on certain claims like jti, or sub, or iss, etc. JWT has a claim named jit which is used to uniquely identify a JSON Web Token. For example: If it is known that a particular token with a specific jit is compromised, authorization rules can be added to revoke the token with a particular jit.

Logs and Troubleshooting

Virtual server logs available on Avi Load Balancer can be used to troubleshoot the JWT validation issues.

To view the reason for various response codes generated by Avi Load Balancer,

  1. Navigate to Templates > Virtual Services

  2. Click on the required virtual service and go to Logs.

  3. Select the option Significant.

Some of the errors that Avi Load Balancer generates are as discussed below:

Error

Response Code

Explanation

Authorization Header Missing

403

Authorization header is missing



Wrong or Unknown User

4xx

The JWT issuer is not known or not supported by Avi Load Balancer



Wrong Audience

4xx

JWT is not issued for the selected application



Login to the Avi Load Balancer CLI and use the show virtualservice <virtual service name> stats command to check the various statistics associated with JWT validation.