Let users authenticate with your app by using an access token from ORY Hydra.

You might control access to your APIs with access tokens. Users can authenticate and authorize access through an OpenID Connect (OIDC) compliant authentication system, such as ORY Hydra. The authentication system issues an access token. Users add the access token in their requests to your app.

Gloo Mesh Gateway accepts the request and validates the token by using the authentication system’s introspection endpoint. If the access token is authorized to perform the requested action, the request is returned successfully. Otherwise, the request is denied.

Before you begin

  1. Set up Gloo Mesh Gateway in a single cluster.
  2. Install Bookinfo and other sample apps.
  3. Configure an HTTP listener on your gateway and set up basic routing for the sample apps.

  4. Make sure that the external auth service is installed and running. If not, install the external auth service.

      kubectl get pods -A -l app=ext-auth-service
      

Install Hydra

To set up authentication, you need an OpenID Connect (OIDC) provider to use with Gloo Gateway. For demonstration purposes, you can deploy ORY Hydra in your demo cluster.

  1. Add the Ory Helm repository to your cluster.

      helm repo add ory https://k8s.ory.sh/helm/charts
    helm repo update
      
  2. Deploy the Hydra Helm chart.

      helm install \
        --set 'hydra.config.secrets.system={$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | base64 | head -c 32)}' \
        --set 'hydra.config.dsn=memory' \
        --set 'hydra.config.urls.self.issuer=http://public.hydra.localhost/' \
        --set 'hydra.config.urls.login=http://example-idp.localhost/login' \
        --set 'hydra.config.urls.consent=http://example-idp.localhost/consent' \
        --set 'hydra.config.urls.logout=http://example-idp.localhost/logout' \
        --set 'ingress.public.enabled=true' \
        --set 'ingress.admin.enabled=true' \
        --set 'hydra.dangerousForceHttp=true' \
        --set 'image.tag=latest-sqlite' \
        hydra-token-example \
        ory/hydra
      
  3. Verify that the Hydra pods are running. In the service ports, note that admin endpoint runs on port 4445 and the public endpoint runs on port 4444. You use the admin endpoint to create a client ID and password and to validate the token. You use the public endpoint to generate an access token.

      kubectl get all -l app.kubernetes.io/name=hydra -n default 
      

    Example output:

      NAME                                      READY   STATUS    RESTARTS   AGE
    pod/hydra-token-example-cdcf57f87-zpq9q   1/1     Running   0          111s
    
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    service/hydra-token-example-admin    ClusterIP   10.108.3.142    <none>        4445/TCP   111s
    service/hydra-token-example-public   ClusterIP   10.108.12.219   <none>        4444/TCP   111s
    
    NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/hydra-token-example   1/1     1            1           111s
    
    NAME                                            DESIRED   CURRENT   READY   AGE
    replicaset.apps/hydra-token-example-cdcf57f87   1         1         1       111s
      

Create the OIDC credentials

Now that you have an OIDC provider running, you can create the credentials.

  1. Enable port-forwarding for the administrative endpoint on port 4445.

      kubectl port-forward deploy/hydra-token-example 4445
      
  2. In a new tab in your terminal, send a request to the admin endpoint to create a client ID and secret.

      curl -X POST http://127.0.0.1:4445/clients \
      -H 'Content-Type: application/json' \
      -H 'Accept: application/json' \
      -d '{"client_id": "my-client", "client_secret": "secret", "grant_types": ["client_credentials"]}'
      

    Example output:

      {"client_id":"my-client","client_name":"","client_secret":"secret","redirect_uris":null,"grant_types":["client_credentials"],"response_types":null,"scope":"offline_access offline openid","audience":[],"owner":"","policy_uri":"","allowed_cors_origins":[],"tos_uri":"","client_uri":"","logo_uri":"","contacts":null,"client_secret_expires_at":0,"subject_type":"public","jwks":{},"token_endpoint_auth_method":"client_secret_basic","userinfo_signed_response_alg":"none","created_at":"2022-05-24T21:36:11Z","updated_at":"2022-05-24T21:36:10.78725Z","metadata":{}}
      
  3. Enable port-forwarding for the public endpoint on port 4444.

      kubectl port-forward deploy/hydra-token-example 4444
      
  4. In a new tab in your terminal, send a request to the public endpoint to create an access token. The access token uses the client ID and secret that you created in the previous step.

      curl -X POST http://127.0.0.1:4444/oauth2/token \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      -H 'Accept: application/json' \
      -u my-client:secret \
      -d 'grant_type=client_credentials' | jq .access_token -r
      
  5. Set the access token as an environment variable.

      #SET VARIABLE
    export HYDRA_ACCESS_TOKEN=<_EB6xI-hnCryL_D...>
      
  6. Check that the access token works by using the introspection path of the admin endpoint. The introspection path is the same path that Gloo Gateway uses to check the validity of access tokens.

      curl -X POST http://127.0.0.1:4445/oauth2/introspect \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      -H 'Accept: application/json' \
      -d "token=$HYDRA_ACCESS_TOKEN" | jq
      

    Example output:

      {
      "active": true,
      "client_id": "my-client",
      "sub": "my-client",
      "exp": 1653432108,
      "iat": 1653428508,
      "nbf": 1653428508,
      "aud": [],
      "iss": "http://public.hydra.localhost/",
      "token_type": "Bearer",
      "token_use": "access_token"
    }
      

Configure an OAuth policy

  1. Create an external auth server to use for your policy.

      kubectl apply -f - <<EOF
    apiVersion: admin.gloo.solo.io/v2
    kind: ExtAuthServer
    metadata:
      name: ext-auth-server
      namespace: bookinfo
    spec:
      destinationServer:
        port:
          number: 8083
        ref:
          cluster: $CLUSTER_NAME
          name: ext-auth-service
          namespace: gloo-mesh
    EOF
      
  2. Create an external auth policy that points to the introspection URL for access token validation.

      kubectl apply -f -<<EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: ExtAuthPolicy
    metadata:
      name: ratings-hydra
      namespace: bookinfo
    spec:
      applyToRoutes:
      - route:
          labels:
            route: ratings
      config:
        server:
          name: ext-auth-server
          namespace: bookinfo
          cluster: $CLUSTER_NAME
        glooAuth:
          configs:
          - oauth2:
              accessTokenValidation:
                introspectionUrl: http://hydra-token-example-admin.default:4445/oauth2/introspect
    EOF
      

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

    SettingDescription
    applyToRoutesUse 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.
    accessTokenValidationConfigure the details to validate the access token. If the token is missing or invalid, Gloo Gateway denies the request. In this example, the introspection URL is set to the OIDC provider value, the Hydra admin port. You can use the internal hostname of the Hydra admin service, because the request comes from Gloo Gateway’s external auth pod that has access to Kubernetes DNS.
  3. Send a request to the ratings app without providing an access token. Because you enabled OAuth, the request fails with a 403 Forbidden HTTP error code.

  4. Send the request again, this time with an invalid token value. Again, the request fails with a 403 Forbidden error code.

  5. Send the request once more, this time with the access token that you previously created. The request succeeds with a 200 HTTP response and the body of the Bookinfo homepage.

Good job, you used an access token to authenticate your request! As you plan your production scenario, keep in mind a few things about access tokens. Your app likely sends a request to get its own access token, instead of you providing one directly in the header of a request. Typically, you scope the access token to certain API actions. Also, access tokens expire. Check the default authorization and expiry settings for Hydra or your identity provider when you set up your apps to authenticate with access tokens.

Cleanup

You can optionally remove the resources that you set up as part of this guide.
  helm uninstall hydra-token-example 
kubectl delete extauthserver -n bookinfo ext-auth-server
kubectl delete extauthpolicy -n bookinfo ratings-hydra