Set up AuthZ with PortalGroups
Use a PortalGroup for claims-based authorization to the APIs in your Portal.
With a PortalGroup, you can set up membership information of specific claims that must be present in the user’s JWT from the OIDC provider before the user gets access to an ApiProduct.
About OIDC
A PortalGroup specifies the claims that must be present in a JWT ID token to allow a user to access specific private APIs and usage plans, and to perform actions, such as to create API keys for these APIs. Therefore, PortalGroups create an additional layer of security for your portal alongside external OIDC authentication.
To configure authorization for private APIs, you must set up authentication with an OIDC provider first. After successful authentication, the OIDC provider returns an ID token and refresh token. The ID token contains the claims that are used to match the user to a PortalGroup. After a matching PortalGroup is found, access to the private APIs and usage plans is granted.
The following image illustrates the authorization flow when trying to create an API key for a private API. Note that this flow assumes that the user is successfully authenticated with an OIDC provider and received an ID token.
Authorization for private APIs with PortalGroups helps you to configure the private APIs that a user can see when logging in to the developer portal. Authorized users can then view the API schema or create API keys to interact with the API. However, PortalGroups cannot be used to configure APIs to require API keys when interacting with the API.
Set up authorization with PortalGroups
To control access to private API products in your developer portal, you set up PortalGroups and specify the conditions that must be met to successfully authorize a user to see the private APIs.
To match a user with a PortalGroup, the user must present an ID token from an OIDC provider. To learn how to integrate your developer portal with an OIDC provider, see Set up external authentication.
Set up an OIDC provider for the developer portal. For example, see Steps 1 and 2 in the Keycloak guide. This step is required to receive the ID token from your OIDC provider and identify the claims that you want to use for your PortalGroup.
Identify the claims in the ID token that you want to match on. For example steps to create a custom claim, see Step 3 in the Keycloak guide. Only if a user presents a token with the right claims, the user is matched with the PortalGroup and is granted access to the private APIs and usage plans that you define in the PortalGroup. The ID token is returned by the OIDC provider during authentication. Depending on the OIDC provider that you use, you can customize the claims that are being returned in the ID token. However, some OIDC providers might not allow you to create custom claims.
Your ID token might have a claim structure that is similar to the following:
{ "exp": 1681133278, "iat": 1681133218, "auth_time": 1681133218, "jti": "3e410301-d9a2-463f-a127-df78a94f87db", "iss": "http://34.xxx.xxx.xxx:8080/auth/realms/master", "aud": "4464fbac-ab29-4c6a-945b-14e4685c0ad4", "sub": "83a467a1-8f4e-4dd6-8fd1-34832ba0a84e", "typ": "ID", "azp": "4464fbac-ab29-4c6a-945b-14e4685c0ad4", "session_state": "aac7790f-036c-4367-b728-1f1d9dc355fe", "at_hash": "2nFLjyWQA2pEANc8zuhwTw", "acr": "1", "email_verified": false, "preferred_username": "user1", "email": "user1@example.com", "X-groups": "users", }
Create a PortalGroup to allow access to the petstore API product for a user that presents an ID token with the
X-groups: users
claim.kubectl apply -f- <<EOF apiVersion: portal.gloo.solo.io/v1 kind: PortalGroup metadata: name: petstore-group namespace: gloo-system spec: membership: - claimGroup: - key: X-groups value: users apiProducts: - name: 'tracks-svc-api-product' namespace: gloo-system EOF
Setting Description membership
The claims that determine whether a user belongs to the PortalGroup. Users must have a JWT ID token with claims that match all the claims in the membership list. claimGroup
Set the claims in the JWT ID token that must be present to successfully include the user in this PortalGroup. Note that the claims that you specify must exist in the ID token that your OIDC provider returns. You have the option to specify one or multiple claim sets. In this example, the ID token must include the X-group: users
claim.apiProducts
Select the ApiProducts that the user can view in the developer portal after the user is matched with this PortalGroup. In this example, the PortalGroup gives members access to only the Tracks ApiProduct in the gloo-system
namespace.Verify that the claim is set for the selected ApiProducts in the PortalConfig. If not, you might need to update the ApiProduct selector.
kubectl get portalconfigs -A -o yaml | grep claimGroups -A3
Example output:
claimGroups: - claims: - key: X-groups value: users
Send a request to the
/v1/api-products
endpoint to list the ApiProducts that you have access to. Note that in your CLI output, only the Tracks API is listed. The private Pet Store API is hidden because no ID token with the right claims is presented in the curl request.Example output: Notice that only the
Pet Store
ApiProduct is returned.{ "apiKeyEnabled": false, "apiProductMetadata": { "imageURL": "https://raw.githubusercontent.com/solo-io/gloo/8d9df95602c506067d49db9b1447b4003b19a070/docs/content/img/portal/petstore-food-bowl-collar.png" }, "id": "22faf351-1e1b-47a6-9b7c-865d056e2960", "name": "Pet Store", "oauthEnabled": false, "versionsCount": 1 }
Get an ID token for your user from your OIDC provider.
Keycloak example:
export USER1_TOKEN=$(curl -Ssm 10 --fail-with-body \ -d "client_id=${KEYCLOAK_CLIENT}" \ -d "client_secret=${KEYCLOAK_SECRET}" \ -d "username=user1" \ -d "password=password" \ -d "grant_type=password" \ "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" | jq -r .access_token)
Send another request to the
/v1/api-products
endpoint. This time, you provide the ID token that you retrieved in the previous step in theCookie
request header. In your CLI output, verify that you also see the Tracks ApiProduct, because now, you are successfully authenticated and authorized to see this private API.Example output:
[ { "apiKeyEnabled": false, "apiProductMetadata": { "imageURL": "https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/fbf090f7f6e9dd14c1b14d7c274b8611c9b0443e/gloo-gateway/portal/astronauts-image.jpeg" }, "id": "5f659216-af3a-4368-90b5-41144f733885", "name": "Catstronauts Course Tracks", "oauthEnabled": false, "versionsCount": 1 }, { "apiKeyEnabled": false, "apiProductMetadata": { "imageURL": "https://raw.githubusercontent.com/solo-io/gloo/8d9df95602c506067d49db9b1447b4003b19a070/docs/content/img/portal/petstore-food-bowl-collar.png" }, "id": "22faf351-1e1b-47a6-9b7c-865d056e2960", "name": "Pet Store", "oauthEnabled": false, "versionsCount": 1 } ]