Skip to content

OIDC with Okta

We wish to protect the httpbin application with OpenID Connect authentication.

Once authentication is established, we demonstrate how to configure authorization policies for routes based on JWT claims from the user's access token.

This example uses Okta as the identity provider where we define our users and their level of access to the application.

Okta configuration

You will configure two users, one will be a default user with standard access to the application, the other will be a privileged user with access to additional endpoints in the application.

Configure Groups

Create a group named admin.

In Okta:

  • Navigate to Directory and then to Groups.
  • Click the button Add group.
  • Enter the group name.

Configure Users

Create a user with username johndoe@example.com and another with username zeboss@example.com.

In Okta:

  • Navigate to Directory and then to People.
  • Click the button Add person.
  • Enter the details: user type (User), first and last names, the username (above email address).
  • Check I will set the password.
  • Enter a password.
  • Uncheck User must change password on first login.
  • For the zeboss user, also associate them to the group admin via the Groups field.
  • Click Save.

Configure the Application

The following instructions are for the hostname httpbin.esuez.org.

Edit this value for your specific domain.

In Okta:

  • Navigate to Applications and then to Application.
  • Click the button Create App Integration.
  • Select OIDC as the sign-in method, and Web Application for the application type, and click Next.
  • For App integration name, enter httpbin.esuez.org.
  • Specify https://httpbin.esuez.org/oauth2/callback for the Sign-in redirect URIs field.
  • Enter https://httpbin.esuez.org/logout for the Sign-out redirect URIs field.
  • Click Save.

Edit the application as follows:

  • Select the tab named Assignments.
  • Click the Assign button.
  • Select Assign to People and assign both users to the application.
  • Select Assign to Groups and assign the admin group to the application.

In the General tab, make note of the client id and client secret. You will need both to configure the environment variables CLIENT_ID and CLIENT_SECRET.

Configure the Authorization Server

In Okta:

  • Navigate to Security and then to API.
  • Under Authorization Servers select the existing default authorization server.
  • Make note of the issuer URL to set the ISSUER environment variable.
  • Select the Claims tab.
  • Click the button Add Claim.
  • Set the claim name to access.
  • Keep the defaults: include in token type "Access Token", and value type of "Expression".
  • For the expression value, enter: (user == null) ? "default" : user.isMemberOfGroupName("admin") ? "privileged" : "default"
  • Click Create.

The above expression translates admin group membership to the value "privileged"; absence of membership results in the value "default."

Test the token

  • Select the tab Token Preview
  • Select the httpbin app integration, the grant type of authorization code, one of the two users, the the scope named openid
  • Select Preview Token
  • Select the tab named token (that would be the access token)
  • Verify that the payload has a claim named access with value of privileged for the admin user and default for the other user.

Configuring Authentication

Before proceeding, configure your issuer URL, client id, and client secret.

For example:

export ISSUER="https://dev-*****.okta.com/oauth2/default"
export CLIENT_ID="..."
export CLIENT_SECRET="*****"

Kubernetes secret

Create a Kubernetes secret for the client secret:

kubectl create secret generic httpbin-client-secret \
  --from-literal=client-secret=$CLIENT_SECRET

Security policy

Review the following security policy specification:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: httpbin-security-policy
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: httpbin
  oidc:
    provider:
      issuer: "$ISSUER"
    clientID: "$CLIENT_ID"
    clientSecret:
      name: httpbin-client-secret
    redirectURL: "https://httpbin.esuez.org/oauth2/callback"
    logoutPath: "/logout"
    forwardAccessToken: true

We are basically configuring OIDC authentication for the route for the httpbin application.

Apply the policy, with variable substitution:

envsubst < oidc/oidc-policy.yaml | kubectl apply -f -

Test it

  1. Visit the httpbin route. You will be redirected to your identity provider.
  2. Sign in. You will be redirected back to the target application.

Authorization

Review the following augmented security policy specification:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: httpbin-security-policy
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: httpbin
  oidc:
    provider:
      issuer: "$ISSUER"
    clientID: "$CLIENT_ID"
    clientSecret:
      name: httpbin-client-secret
    redirectURL: "https://httpbin.esuez.org/oauth2/callback"
    logoutPath: "/logout"
    forwardAccessToken: true
  jwt:
    providers:
    - name: okta
      issuer: "$ISSUER"
      recomputeRoute: true
      claimToHeaders:
      - claim: sub
        header: x-sub
      - claim: access
        header: x-access
      remoteJWKS:
        uri: "$ISSUER/v1/keys"

We are adding a JWT provider that will populate the header x-access with the value from the access claim (default or privileged).

Apply the policy, with variable substitution:

envsubst < oidc/security-policy.yaml | kubectl apply -f -

Next, expose the "admin" routes only to privileged users:

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin
spec:
  hostnames:
  - httpbin.esuez.org
  parentRefs:
  - name: eg
    sectionName: https
  rules:
  - matches:
    - path:
        type: Exact
        value: /headers
    - path:
        type: Exact
        value: /oauth2/callback
    - path:
        type: Exact
        value: /logout
    backendRefs:
    - name: httpbin
      port: 8000
  - matches:
    - path:
        type: PathPrefix
        value: /
      headers:
      - name: x-access
        value: "privileged"
    backendRefs:
    - name: httpbin
      port: 8000
  - backendRefs:
    - name: invalid-backend
      port: 8080

Above:

  • We give access to the exact endpoint (path) /headers to all authenticated users.
  • For any other path (path prefix of /), we match only if the header x-access is privileged.

Other than the /headers (and oauth) endpoints, non-privileged users will not have routes to any of the other endpoints of the httpbin application.

Apply the claim-based routing policy:

kubectl apply -f oidc/authz-route.yaml

To test the policy:

  • Sign in as a non-privileged user and verify that you can access the /headers endpoint but no other httpbin application endpoints.
  • Sign in as a privileged user and verify that this user has access to all of the httpbin app endpoints.

References