Step 7 - Set up authentication and authorization

In this lab, we will add a security layer in front of our API Gateway. To do so, we will:

  • Add JWT token validation
  • Add JWT claims authorization
../../../_images/archi.png

Note

A JWT token needs to be issued by an OAuth Authorization Server (AS). There are several OAuth AS on the market. Some are IDaaS (Identity as a Service) like Azure AD or Okta. Some others are OSS (Open Source Software) or commercial like Keycloak.

In this lab, we will use Keycloak as our OAuth AS to issue the JWT tokens.


Steps to enable JWT token validation and authorization

Configure Keycloak as a JWT OIDC token issuer

  1. RDP to the Win10 VM (user/user).

  2. Open the Edge Browser and select the Keycloak HTTPS bookmark.

  3. Click on Administration Console.

    ../../../_images/admin_console.png
  4. Login to Keycloak using admin as both the user and password.

  5. On the top left corner, check that the realm selected is Api-app and click on the Clients menu.

  6. Select my-postman

    ../../../_images/clients.png

    Note

    In order to avoid any mistakes during this lab, we created in advance the my-postman client and the secret key (9cabf36d-8eda-4cf8-a362-ccc982408ba7).

  7. In the my-postman client, click on Credentials. You should be able to see the secret key we will use to ask for a JWT token in postman.

  8. Click on Users in the left menu, and click on View all users

    ../../../_images/users.png

    Note

    You should see 2 users, matt (password matt), and fouad (password fouad). At this stage, these users do not have any attributes assigned.

  9. Click on the matt ID to edit it.

  10. In the Attributes tab, add a new key groups with value employee.

    Warning

    Don’t miss the S at the end of groups.

  11. Click Add -> Click Save

    Warning

    You need to click on Add to add the attribute, and on Save to save the user settings.

    ../../../_images/matt_attributes.png
  12. We will now create our own scope, groups, so that a JWT claim is added into every JWT token with the respective attribute value(s):
    1. Click on Client Scopes -> Create

    2. Name the scope groups -> Click Save -> Click the Mappers tab -> Click Create

    3. Create a new mapper. Use the following values:

      • Name: groups
      • Mapper Type: User Attribute
      • User Attribute: groups
      • Token Claim Name: groups
      • Claim JSON Type: String
      • Add to ID token: ON
      • Add to access token: ON
      • Add to userinfo: ON
      • Multivalued: OFF
      • Aggregate attribute values: OFF
      ../../../_images/mapper.png

      Note

      The configuration above says to add a claim with the name groups and assign it the value from the user attribute groups

    4. Click Save

  13. Leave the Mappers window by clicking on the top left menu Client Scopes

    ../../../_images/mapper_quit.png
  14. Still in Keycloak, add this new scope to the my-postman client:
    1. Click Clients -> my-postman and select the Client Scopes tab

    2. Before adding our new scope groups, let’s have a look in at how the generated JWT token looks like. Click on Evaluate and select matt as the user, then click Evaluate.

      ../../../_images/evaluate.png
    3. Click Generated Access Token, and check the JWT content.

      ../../../_images/jwt_no_groups.png

      Note

      As you can see, there is no groups claim in this JWT token

    4. Click on the Setup sub-menu (next to the Evaluate sub-menu), select the groups scope under Available Client Scopes and click Add Selected to move the scope into the Assigned Default Client Scopes.

      ../../../_images/scopes.png
    5. Move back to the Evaluate sub-menu, select matt as a user, now you can see a groups: employee attribute value in Generated Access Token for matt user

      ../../../_images/claim_groups.png

Warning

Congrats! We are now ready to configure NGINX Controller to check the groups claim values and conditionally grant access to our API endpoints.


Create an Identity Provider in NGINX Controller

A JWT token is a readable token signed by a public/private key workflow. Keycloak (or any other Oauth AS) provides you with either a private secret key or a JWKS url.

A JWKS url is a public URL to retrieve and download the public keys used to sign the JWT token. The Keycloak JWKS url is http://10.1.1.8:8080/auth/realms/api-app/protocol/openid-connect/certs, and the content looks like:

{
    "keys": [
        {
            "kid": "as8gYx18yAyuzBOD9UiVp-ndr-aGmnSwfOqscHGuJUM",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "nJY5azyX0e5ropzKVBmFH3kt3vftV1iG7O157WyxgFU8hd22wM5vJwmkodBy91Yc3M6qcag9Gi3YMvKnFQF6OrYeaOg7ePWnabAhyhMjATWtnypbRcqM9AyyBekphNhpuNT2Mlqo7eYIt85VUT9iv3upLNy2PZ1W_iAYTh5f-RQukWAagMX7vTWQ4mrUvKfKc7RCc-ikBToaSEte193ckjRqawSLYoHRs2vAeywZYaPFXeIuBaFKglpV051dNwcJFfWMCNmbIJ0xTlXJP2HfQ1AaY7u5SFXnkcX-pkt2PBTDrWqPahZhDQjCstr3M_qbpYd6LUls5z-yhiaHQ4JW1w",
            "e": "AQAB",
            "x5c": [
                "MIICnTCCAYUCBgF4fRp2jzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdhcGktYXBwMB4XDTIxMDMyOTA4MjgwOVoXDTMxMDMyOTA4Mjk0OVowEjEQMA4GA1UEAwwHYXBpLWFwcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJyWOWs8l9Hua6KcylQZhR95Ld737VdYhuztee1ssYBVPIXdtsDObycJpKHQcvdWHNzOqnGoPRot2DLypxUBejq2HmjoO3j1p2mwIcoTIwE1rZ8qW0XKjPQMsgXpKYTYabjU9jJaqO3mCLfOVVE/Yr97qSzctj2dVv4gGE4eX/kULpFgGoDF+701kOJq1LynynO0QnPopAU6GkhLXtfd3JI0amsEi2KB0bNrwHssGWGjxV3iLgWhSoJaVdOdXTcHCRX1jAjZmyCdMU5VyT9h30NQGmO7uUhV55HF/qZLdjwUw61qj2oWYQ0IwrLa9zP6m6WHei1JbOc/soYmh0OCVtcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEARr5/4RxFeHMtQxa3soEgQdQ6nCMqUiAKM0V7Upnoo3lTorMiujsi3Iog2olq1r/z4+xdOXTNL6WqNWdGr+z1OFnqzmUl1l+xESNSXBYTUZyeIbLYCjLGCfrzqYJBQvs/ECJ8Rk4mabL1tLDAUOiEUhvlJgiiNLWrqhwrpOrdJtlU8rlGk5TRjv+lpWkex9ZqpYKZ4ewHlZSTlAri9Jb+WuxFmw8ksrufmqn4IQ5Oee9O3HL8nadbqgeokY6Rb8U5HKaNDyvuCERfC/wLph+DVJQd1ubG1XvnfRcdGW8e79US+uIxJUQZCY2BN01Y0f89rRmgk5tZ15Fxl6FYeT2Y/Q=="
            ]
            ,
            "x5t": "_qPH5MQIPZ4EmoWlTHv7Ciq28EY",
            "x5t#S256": "V5zhNTYsKPltmTdF9j_LnZfaIgMHCnLJoiNwxpEBUc8"
        }
    ]
}
  1. In NGINX Controller -> Select Services -> Identity Providers -> Create Identity Provider. Use the following values:
    • Name: keycloak
    • Environment: env_prod
    • Type: JWT
    • JWT Settings: Enter a URL for the file's location
    • URL: http://10.1.1.8:8080/auth/realms/api-app/protocol/openid-connect/certs
  2. Click Submit
../../../_images/idp.png

Add authentication to the /colors API endpoint

  1. In NGINX Controller -> Select Services (from top left Nginx menu) -> APIs -> api-sentence -> Edit the api-sentence-v3 published API

    ../../../_images/edit_auth_colors.png
  2. In the Routing menu, edit the Security Settings for the cp-colors-v3 component

    ../../../_images/edit_sec_colors.png
  3. Click Add Authentication

    ../../../_images/add_auth.png
  4. Use the following values:

    • Identity Provider: keycloak
    • Credential Location: BEARER

    Note

    This setting means that the JWT token is expected to be present in the Authorization: Bearer HTTP header

  5. Click Done

  6. Click Submit -> Submit again to validate the config and push it to the NGINX instance.

Note

We have not enabled conditional access for now.


Test the authentication protected API

  1. RDP to the Win10 VM (user/user).

  2. Open Postman, select the API Sentence Generator v3 collection, and select the GET Colors v3 request.

  3. Run the request, you should get a 401 Authorization Required response. This is because there is no JWT token in the request.

  4. Request a JWT token from Keycloak
    1. In the Authorization tab, under Type, select OAuth 2.0, and click the orange Get New Access Token button (at the bottom of the right side menu).

      Note

      We already configured Postman as our OAuth client behind the scenes. You can retrieve the Client ID and secret from the my-postman Keycloak client configuration.

      ../../../_images/postman_client.png
    2. Authenticate as matt (password matt).

      ../../../_images/auth.png
    3. Click on Use Token orange button. The JWT token is now saved and ready to be used.

    4. Send the request again. It should pass.


Add conditional access to the /colors API endpoint

The next step is to add Conditional Access for employee users only. This way, any JWT token without the claim groups and the value employee can’t reach the /colors API Endpoint.

  1. In NGINX Controller -> Select Services (from top left Nginx menu) -> Select APIs -> api-sentence -> Edit the api-sentence-v3 published API.

  2. In the Routing menu, edit the Authentication setting for the cp-colors-v3 component.

  3. Turn on Enable Conditional Access.

    ../../../_images/cond_access1.png
  4. Configure it so that only a JWT with a group: employee claim is allowed. Use the following values:

    • Policy Type: Allow when
    • Source Data Type: JWT claim
    • Source Data Value: groups
    • Comparison Type: Contains
    • Value: employee
    • Failure Response: 403
    ../../../_images/cond_access2.png
  5. Click Submit -> Submit again to validate the config and push it to the NGINX instance.


Test the conditional access protected API

  1. RDP to the Win10 VM (user/user).

  2. Open Postman, select the API Sentence Generator v3 collection, and select the GET Colors v3 request. If necessary, request a new token for user matt (password matt).

    Note

    Don’t be surprised if you don’t see the popup window asking for the credentials. It means Postman still has a session opened with Keycloak for matt.

  3. Use the token and send the request. It should pass.

  4. Now, try with another user that’s not part of the employee group.
    1. Click on Clear cookies (down next to the orange Get New Access Token button).

      ../../../_images/clear_cookies.png
    2. Request a new token but with fouad (password fouad).

    3. Use the token and send the request. You will get a 403 Forbidden.

    4. The response code/message should be 403 Forbidden. Note that this is different from the response code 401 Authorization Required we received when the JWT was not present.

    5. Go back to the Get New Access Token menu. Copy the token generated by Postman, and paste it in https://jwt.io (bookmark in Edge Browser) in order to see the claims contained in the JWT.

      Note

      As you can see, fouad is not part of the employee group, so he can’t access the /colors endpoint.

      ../../../_images/jwtio.png

Attention

Congrats! You enabled authentication in front of the /colors API endpoint, and you then implemented conditional access based on a JWT claim!