Self-Service User Registration with Gloo Portal and Okta
Gloo Portal users often ask if there is a way to configure self-service registration for new portal users. Imagine a use case like this: We have APIs that we’d like to publish externally in a way that is freely accessible for new users. But we don’t want anonymous users or bots pounding away at our servers. We’d like to require users to register to use our service, and we’d like to keep the administrative burden to a minimum. Is there some way we can make the registration process self-service?
The short answer to this question is YES. This post will explore one approach to achieve this using the popular identity management platform Okta. Okta supports the OpenID Connect (OIDC) standard and allows users to configure their application for self-service registration. (Okta certainly isn’t the only IdP option for configuring self-registration with Gloo Edge, but it is a popular option among Solo customers. It seems very likely that Keycloak among others could support this use case as well.)
In this post, we’ll walk step-by-step through the process of building out a Petstore Portal with public APIs that allow users to register themselves. We’ll walk through the configuration of both the Portal itself and our Okta application, and then we’ll test it out in our Portal sandbox.
Prerequisites
You’ll need a Kubernetes cluster and associated tools, plus an instance of Gloo Edge Enterprise to complete this guide.
We use Google Kubernetes Engine (GKE) with Kubernetes v1.18.16 to test this guide, although any recent version with any Kubernetes provider should suffice. If you prefer to work locally instead of a remote cluster, we’ve have good success with Kind. If you go the Kind route, use these instructions for your installation of Gloo Edge.
We use Gloo Edge Enterprise v1.9.0 as our API gateway. Use this guide if you need to install Gloo Edge Enterprise. If you don’t already have access to the Enterprise bits of Gloo Edge, you can request a free trial here.
Gloo Portal is available as an element of the Gloo Edge Enterprise subscription. But since not all customers use it, it is packaged as a separate installation from the core Edge API Gateway. We are using Portal v1.1.1 for this exercise. Follow this guide to install Portal with Gloo Edge as its deployment target.
Note that Gloo Portal also supports deployment to Istio ingress gateways in addition to Gloo Edge. However, in this blog post we’ll focus strictly on deployment to Gloo Edge.
Establish the Initial Portal
We will begin by establishing the initial version of the Petstore Portal, which will allow anonymous access to its endpoints with no authentication required.
Deploy the Petstore App
First, let’s deploy the Petstore application to our Kubernetes cluster.
% kubectl apply -n default -f \ https://raw.githubusercontent.com/solo-io/gloo/v1.9.0/example/petstore/petstore.yaml % kubectl -n default rollout status deployment petstore deployment "petstore" successfully rolled out
Configure the Portal Components
If you have not used Gloo Portal at all in the past, you might benefit from walking through these two detailed step-by-step guides to creating the Kubernetes custom resources that comprise your first basic Portal.
However, if you’ve built basic Gloo Portal configurations in the past, you can skip the two Getting Started guides and arrive at the same place using the command below. It will build all of the Portal components from the guides above, including the following Kubernetes custom resources:
- an
APIDoc
to wrap the OpenAPI interface of the Petstore application, - an
APIProduct
to apply policies to those endpoints and package them for distribution, - an
Environment
to declare which APIProducts will be deployed to which compute environments, and - a
Portal
to manage the specifics of how the generated web user interface will be presented to users.
kubectl apply -f \ https://raw.githubusercontent.com/jameshbarton/solo-resources/main/portal-self-reg/0-apidoc-prod-envt-portal.yaml
Configure DNS Rules
If you used the single kubectl
command above to create the Portal artifacts, then you likely do not have the necessary network configuration in place. In order to visit the Portal being served at our domain petstore.example.com
, we’ll need to make sure a DNS rule exists that will resolve that domain to that address.
There are many ways to set up DNS rules for the domains defined in our Environment and Portals. In production environments, you will probably want to use your Cloud Provider’s DNS solution.
For the purposes of this setup, modifying your local /etc/hosts
file with an entry to manually resolve the Environment and Portal domains will be sufficient.
Let’s add entries for the api.example.com
and petstore.example.com
domains, substituting INGRESS_HOST
with your IP address for these hostnames. If you need support in determining the INGRESS_HOST
for your environment, review this section in Part 1 of the Portal Getting Started Guide.
cat <<EOF | sudo tee -a /etc/hosts # Added for the Solo.io Gloo Portal Guides ${INGRESS_HOST} api.example.com ${INGRESS_HOST} petstore.example.com EOF
Confirm API Execution
If the Petstore app is running as expected, and all of the Portal elements are properly configured, then we should be able to exercise the currently unsecured API endpoints.
% curl http://api.example.com/api/pets [{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
Configure Okta for Self-Registration
Establish Okta Account
Establish Okta Application
Web
type application, set a Sign on method
of OpenID Connect
, and gave the application the name Petstore
.Login redirect URIs
, for which we provided a single value http://petstore.example.com/callback
. For more details on creating Web
type application integrations with Okta, we found this guide helpful. Our final Okta Petstore
application profile looked like this.Configure an Okta User Group (and maybe some Users)
When you establish an Okta application, you get one user group for free, the Everyone
group. We could use that default group to drive this exercise. But instead let’s make this a bit more realistic by creating a separate group to hold our set of users (including self-registered ones) that will have access to our “public” Petstore API. Let’s establish a group called PetstoreUsers
. Navigate to Directory > Groups
and establish the PetStoreUsers
group.
You may also want to create some Okta Users and assign them to the PetstoreUsers
Group, although that isn’t strictly required since soon we’ll be able to create Users dynamically from our web interface using self-service registration.
Configure a Groups Claim from the Petstore Application
Gloo Portal expects there to be a claim presented from the IdP as part of an ID token in the OIDC auth flow that identifies the Groups that a particular authorized user is part of. More information on how this works in Okta is presented here. Okta does not present this claim by default.
So we need to enable this by specifying a custom groups
claim in two different places, the Okta Application configuration and the Authorization Server configuration.
First, let’s tackle the Application configuration. Navigate to Applications > Applications
in the admin console and click through to the Petstore
application. Switch to the Sign On
tab and edit the Groups claim filter
to specify the claim name is groups
and that it should match the regex pattern .*
. In other words, all group names that are part of the application will be passed back to the Portal in the groups
claim.
Second, we’ll configure the Authorization Server to pass back the groups
claim with just the PetstoreUsers
group name. Navigate in the admin console to Security > API
and click through to the default
Authorization Server config. Switch to the Claims
tab and add a groups
claim as shown below.
Note that we specified the name of the claim as groups
, we changed the token type
value from the default to ID Token
, and we specified a Filter
value to only include groups whose names start with the string Petstore
, which will match our group named PetstoreUsers
.
Enable Okta Self-Registration on Account
By default, Okta accounts are not enabled for self-service registration (SSR). In this section, we will walk through the steps to configure this. For more details, the Okta guide to managing self-registration settings is quite helpful.
First, we will navigate the Okta admin console to Directory > Self-Service Registration
and enable the feature.
After enabling SSR, we need to customize the settings for our application. We specify the Assign to group
as PetstoreUsers
, the user group we created earlier in this exercise, so that any users created by SSR will automatically be placed into the group that we will configure to have access to the Petstore APIs.
And just to save a bit of time for this exercise, we will also turn off the default setting that the user must verify their email address in order to be activated as a member of the group. Okta will still send a confirmation email to the specified address, but it will not require any action from the newly registered user in response.
Enable Okta Self-Registration on Petstore Application
Not only is self-registration disabled by default on Okta accounts, it is also disabled by default on the Applications that comprise those accounts. In this section, we will walk through the process of enabling and configuring SSR on the Okta Petstore Application.
First, use the Okta admin console to navigate back to the Petstore Application and switch to the Assignments
tab. You should notice that the SELF SERVICE
panel is marked Disabled
. Edit those settings to allow users to request access to the application, and to mark administrator approval as Not Required
.
Also on the Assignments tab, select Groups and assign the PetstoreUsers
group that we created earlier to this application. Your final Assignments tab interface should look something like below.
Integrate Petstore Portal with Okta
In this section, we’ll walk through the steps for configuring OIDC integration with Okta, which will allow us to delegate auth decisions to the IdP.
Establish Okta Client Secret
The OIDC standard specifies two bits of credentials that an OIDC client needs to present to its provider, a client ID and a client secret. Okta provides this information on its admin console’s Application detail interface.
We will use the client secret from Okta to configure a corresponding Kubernetes Secret
, which we will apply to our Portal config as part of the OIDC integration.
export CLIENT_SECRET=your-oidc-client-secret-here cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Secret metadata: name: petstore-portaloidc-secret namespace: default data: client_secret: "$(echo $CLIENT_SECRET | base64)" EOF
Configure Portal for Okta Auth Delegation
Our initial Portal had no authorization configured at all. There is an internal HTTP basic auth mechanism that we could use, but that is typically used just for testing purposes. The internal mechanism is missing self-registration and a host of other features found in enterprise IdP’s like Okta.
We will now add to our Portal
configuration an oidcAuth
stanza to connect with our Okta application. You’ll need to fill in the client ID shown in Okta and the correct host for your developer account in the issuer URL. Ensure that you include the groups
value in the additionalScopes
field so that the group claims are included in the request.
cat <<EOF | kubectl apply -f - apiVersion: portal.gloo.solo.io/v1beta1 kind: Portal metadata: name: petstore-portal namespace: default spec: banner: fetchUrl: https://i.imgur.com/EXbBN1a.jpg customStyling: {} description: The Gloo Portal for the Petstore API displayName: Petstore Portal domains: - petstore.example.com - petstore.example.com:$INGRESS_PORT favicon: fetchUrl: https://i.imgur.com/QQwlQG3.png primaryLogo: fetchUrl: https://i.imgur.com/hjgPMNP.png publishedEnvironments: - name: dev namespace: default staticPages: [] portalUrlPrefix: http://petstore.example.com:$INGRESS_PORT/ oidcAuth: clientId: 0oaksnsdvwTd1b5wR5d6 # uses client ID from Okta application clientSecret: name: petstore-portaloidc-secret # uses client secret from Okta application namespace: default key: client_secret groupClaimKey: groups # reads the "groups" claim we configured to pass with Okta ID token # Issuer info available at your Okta's account .well-known OpenId config URL # Example: https://dev-2933640.okta.com/oauth2/default/.well-known/openid-configuration additionalScopes: - groups issuer: https://dev-2933640.okta.com/oauth2/default EOF
Configure Portal Group to Shadow Okta Group
Finally, we will configure a Portal Group
Custom Resource to shadow the PetstoreUsers
group that we created to hold the users of our public API, including the self-registered ones.
cat <<EOF | kubectl apply -f - apiVersion: portal.gloo.solo.io/v1beta1 kind: Group metadata: name: oidc-group namespace: default spec: accessLevel: apiProducts: - name: petstore-product # identify APIProducts accessible to this group namespace: default environments: - name: dev # identify Environments in which this APIProduct is accessible to this portal namespace: default portals: - name: petstore-portal # identify Portals that will be accessible to this group namespace: default oidcGroup: groupName: PetstoreUsers # identifies OIDC group that this group represents EOF
Test Self-Registration with the Petstore Portal
Let’s see how self-registration works in practice by visiting our portal at http://petstore.example.com.
Click through the Login
button and then Log in with OpenID Connect
. This redirects you to an Okta login dialog as shown below. Note in particular the Sign up
link at the bottom of the dialog, which is provided because we configured Okta for self-service registration.
Click through the Sign up
link, provide the information requested, and click Register
.
When everything is configured correctly, your self-registered user will be added to the PetstoreUsers
group and you will be redirected back to the portal home. But now you will notice that you are signed in to the portal with the email address of the newly registered user.
In addition to being added to the Portal, you should also receive a verification email from Okta. Given the way that we configured SSR in Okta, this does not require confirmation by the new user. There is a Verify Account
button in the Okta-generated email, but portal use is not predicated on verification. This message is simply a notification. We could have configured Okta to require user confirmation but chose against it just to keep this process as simple as possible.
Play in the Portal Sandbox
Now that we are authenticated to the Petstore Portal, we can play in the portal’s execution sandbox. Click through View APIs
on the portal home page and click into the v1
sandbox. You should see 4 operations listed there in a familiar Swagger-like style. (The same type of interface is also presented for the newer gRPC service support as well.)
Click through the GET /api/pets
operation and Try it out
followed by Execute
. You should see a response from the endpoint identical to what we saw earlier in this exercise.
Congratulations! You have now configured a customized Petstore API Portal that supports self-service registration of new users with Okta.
Learn More
In this blog post, we walked step-by-step through the process of building out a Petstore Portal that uses OIDC integration with Okta to allow users to register themselves. We established all of the Portal elements, we configured an Okta application from scratch, and we tested it out in our Portal sandbox.
And we are just scratching the surface of features we could deploy to this portal. For example, in a perfect world we might want our public API users to be rate-limited and require them to generate API Keys so that we can better track and control their usage. Creating a Usage Plan is an easy way to add these capabilities.
- Explore the documentation for Gloo Portal
- Request a live demo or trial for Gloo Edge Enterprise with Gloo Portal.
- See video content on the solo.io YouTube channel.
- Questions? Join the Solo.io Slack community and check out the community #gloo-portal channel.