Provider example
Learn how to use a JWT from an IAM provider for claims-based authentication.
In the previous basic JWT guide, you created a JWT filter with an inline JWKS and used your own JWTs to authenticate. Now, learn how to use an IAM provider to enforce a JWT filter with role-based access control (RBAC). This way, users can log in with their own credentials to authenticate to your services.
Before you begin
Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.
Get the external address of the gateway and save it in an environment variable.
Step 1: Set up an IAM provider
Complete one of the OAuth guides to set up an IAM provider, such as Auth0 or Google. The guides cover the following steps.
If you do not already have one, create an account with the IAM provider.
Create the auth app in the IAM provider.
Skip the rest of the guides that involve creating an AuthConfig for an OAuth filter. Instead, you create a JWT filter in this guide.
Make sure that you have the following details for your IAM provider.
- The issuer domain of the IAM provider.
- The port that the issuer domain listens on, such as 443 for HTTPS.
- The JWKS endpoint of the issuer domain.
- To get a JWT to test the steps, you typically need the client ID and secret of the auth application, the auth endpoint, as well as user credentials.
Example endpoint values by IAM provider:
Step 2: Create a JWT filter
Use a JSON Web Key Set (JWKS) endpoint to get the email
claim information of the JWT from the IAM provider. The claim is placed in an email
header that you use to enforce fine-grained RBAC decisions.
Create an Upstream to expose the endpoint of your IAM provider.
kubectl apply -f- <<EOF apiVersion: gloo.solo.io/v1 kind: Upstream metadata: name: jwks-upstream namespace: gloo-system spec: static: hosts: # The host domain where the IAM provider publishes the JWKS endpoint. - addr: ${DOMAIN} port: 443 EOF
Create a VirtualHostOption with the following JWT rules. Note that instead of the VirtualHostOption, you can also use a RouteOption. This way, the JWT rules apply only to the route that the RouteOption configures. The JWT rules of a VirtualHostOption apply to each route along the same host that the gateway listens on (unless overridden by a RouteOption). For more information, see the Policy Overview.
kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: VirtualHostOption metadata: name: jwt-vho namespace: gloo-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http namespace: gloo-system options: jwtStaged: beforeExtAuth: providers: auth0: issuer: https://dev-1234567.us.auth0.com/ tokenSource: headers: - header: jwt claimsToHeaders: - claim: email header: x-solo-claim-email jwks: remote: url: https://dev-1234567.us.auth0.com/.well-known/jwks.json upstreamRef: name: jwks-upstream namespace: httpbin EOF
Review the following table to understand this configuration.
Setting Description targetRefs
Select the Gateway that you want to configure with this virtual host. The example uses the http
gateway that you configured as part of the getting started.jwtStaged
Configure the rules for the JWT filter. The staged JWT lets you select whether to apply the JWT filter before or after external authentication. In this example, the JWT filter applies before external auth. providers
Configure the details of your IAM provider, such as auth0
in this example.issuer
Enter the issuer domain of the IAM provider. This value must match the ISS
claim in the JWT that the IAM provider returns. Common errors such asJwt issuer is not configured
might indicate a different issuer, such as forgetting a trailing slash.tokenSource
Specify where the JWT token is retrieved, such as the jwt
header in this example.claimsToHeader
Extract and add claims from the JWT as headers in the response. In this example, the email
claim from the JWT is added to anx-solo-claim-email
header that you use in a later step.jwks
The remote URL is the JWKS endpoint from your IAM provider, such as the Auth0 example. If you use a different IAM provider, update the endpoint accordingly. You created the Upstream in the previous step. Create an HTTPRoute for the httpbin app on the same gateway as the VirtualHostOption configures. If you used a RouteOption instead, make sure to add an
ExtensionRef
filter that selects the RouteOption.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-jwt-route namespace: httpbin spec: parentRefs: - name: http namespace: gloo-system hostnames: - extauth.example.com rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: httpbin port: 8000 EOF
Send a request to the protected httpbin route without a JWT. Verify that you get back a
401 Unauthorized
error code.curl -i http://extauth.example.com:8080/get
Example response:
HTTP/1.1 401 Unauthorized Jwt is missing
Follow your IAM provider’s docs to get a JWT through an authorization code flow, and save the ID token in an environment variable.
- To get a JWT, you often need the client ID and secret of the auth application, as well as user credentials.
- Make sure that you get back a JWT that includes the scope that you configured in the JWT filter, like the
email
scope. Typically, you add the scopes that you need in a field such asscope: openid email
. - For steps to get a JWT, follow your provider’s documentation. For example, you might use the Auth0, Google, Keycloak, or Okta guides along with a tool to help get the auth code that you exchange for the token, such as the OpenID Connect Debugger.
export TOKEN=<id_token>
Repeat the request to your httpbin app. This time, include the JWT that you just created as part of the
jwt
header.curl -i http://extauth.example.com:8080/get -H "jwt: <TOKEN>"
Example output: Verify that you get back a 200 success status code. Notice that the
email
scope from the claim is added to theX-Solo-Email-Claim
header that you included in the JWT filter. In the example, the user email isdocs@solo.io
.HTTP/1.1 200 OK { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "extauth.example.com:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Solo-Claim-Email": [ "docs@solo.io" ] }, ... }
Step 3: Add RBAC rules
Now that you extracted the email
claim from the JWT, apply RBAC rules to restrict access.
Update the VirtualHostOption with the following RBAC rules. Note that instead of the VirtualHostOption, you can also use a RouteOption. This way, the RBAC rules apply only to the route that the RouteOption configures. The RBAC rules of a VirtualHostOption apply to each route along the same host that the gateway listens on (unless overridden by a RouteOption). For more information, see the Policy Overview.
kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: VirtualHostOption metadata: name: jwt-vho namespace: gloo-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http namespace: gloo-system options: jwtStaged: beforeExtAuth: providers: auth0: issuer: https://dev-1234567.us.auth0.com/ tokenSource: headers: - header: jwt claimsToHeaders: - claim: email header: x-solo-claim-email jwks: remote: url: https://dev-1234567.us.auth0.com/.well-known/jwks.json upstreamRef: name: jwks-upstream namespace: httpbin rbac: policies: viewer: permissions: methods: - GET pathPrefix: /anything principals: - jwtPrincipal: claims: email: docs@solo.io EOF
Review the following table to understand this configuration.
Setting Description permissions
Restrict permissions of the RBAC role. In this example, the viewer role is restricted to use only the GET
method along the/anything
endpoint.principals
Configure the principals that the RBAC rules apply to. In this example, the email claim is used to restrict permissions for the example docs@solo.io
user.Repeat the request to your httpbin app with the JWT. This time, the request is denied because you tried to access an endpoint that you are no longer authorized to (
/get
).curl -i http://extauth.example.com:8080/get -H "jwt: <TOKEN>"
Example output:
HTTP/1.1 403 Forbidden RBAC: access denied
Send a
GET
request to your httpbin app along the/anything
endpoint that you have access to. This time, the request succeeds.curl -i http://extauth.example.com:8080/anything -X GET -d "test: This is anything." -H "jwt: <TOKEN>"
Example output:
HTTP/1.1 200 OK { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "extauth.example.com:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Solo-Claim-Email": [ "docs@solo.io" ], "form": { "test: This is anything.": [ "" ] }, }, ... }
Cleanup
You can optionally remove the resources that you set up as part of this guide.
kubectl delete Upstream -n gloo-system jwks-upstream
kubectl delete VirtualHostOption -n gloo-system jwt-vho
kubectl delete HTTPRoute -n httpbin httpbin-jwt-route