Development / Security / Sponsored / Contributed

Implement Delegated Access with OpenID Connect Authentication for Okta Single Sign on

28 Sep 2020 7:24am, by

Gravitational sponsored this post.

Can you imagine having to give Spotify your Facebook login information for just an email address?!

Virag Mody
Virag joined Gravitational in January of 2020, after co-founding a software code auditing company for Ethereum applications. Having joined Gravitational, Virag continues to learn about trending technologies and produces high quality written and video content. In his free time, Virag enjoys rock climbing, video games and walking his dog.

Of course not. There has to be a better way. The concept we are looking for here is Delegated Access. How can we delegate some degree of access to a third party entity without having to provide login credentials? That’s what OAuth does. But one thing the protocol does not do is communicate identifiable information about who is requesting privileges. There is a profound difference between granting Spotify access to your Facebook account data and letting Spotify make a post as you. By introducing an ID token, OpenID Connect Authentication (OIDC) adds an authentication feature to OAuth’s powerful authorization utility.

By running through a sample OIDC implementation to support Okta Single Sign On (SSO) for Teleport, we will see how the introduction of one additional token does what OAuth could not.

Case Study: Okta SSO for Teleport

OAuth uses different Grants and Flow to determine the sequence of events. We will look at the most common type, the Authorization Code Grant, and go through step by step.

Step 1

Teleport prompts the user to log in via their organization’s SSO provider. In this case, let us use Okta as our IDP.

Step 2

The Teleport user clicks “Log In” and is redirected to Okta’s authorization API endpoint with the following parameters included in the HTTPS request:

What do these parameters mean?

  • authorization_server is the URL that Okta is exposed to. All IDPs will provide a URL to redirect to, usually an API. For Okta, this is https://${yourOktaDomain}/oauth2/default/v1/authorize
  • response_type=code will let the Okta know that Teleport expects an authorization code.
  • client_id provides a string to Okta, which can check against a registry of authorized clients. IDPs like Okta will require clients to be registered to help identify them. Let’s use 12345 as Teleport’s registered ID.
  • redirect_uri informs Okta which pre-configured URL to direct the Teleport user back to, with all the variables that Teleport needs. For this example, we can take the sample redirect URL provided in the Gravitational documentation as https://proxy.example.com:3080/v1/webapi/oidc/callback
  • scope defines the limitations in accessing resources. For OAuth, these scopes are internally defined by the resource application. But recall that OIDC was created to standardize the way to get rudimentary identity information. At minimum, we must use the standard claim openid and perhaps an additional standard claim, email, from Figure 6.
  • state is a string randomly generated by Teleport and passed back and forth with the Okta. By passing this string, both Teleport and Okta know they are speaking to the same device between communications. For this example, let’s say the state string is syl (my dog’s name).

Putting together all these parameters, the URI a Teleport user is directed to after accepting the login prompt will look like:

Step 3

Once Okta receives the query, it will verify the client_id against an internal registry for the Teleport application. Knowing Teleport is expecting an authorization code, Okta will send the user back to the redirect URL with the code and the state parameter that was passed. Our next stop is:

Step 4

After receiving the code, Teleport will automatically query the Okta token endpoint to exchange the code for a token with the code, redirect_uri, and client_id parameters included. Two additional parameters are present:

  • grant_type=authorization_code informs Okta the flow is authorization_code
  • client_secret comes from Okta during the client registration process. This string should be secret and not publicly accessible. Because Teleport is hosted on our own infrastructure, which we know to be safe, we feel comfortable passing this parameter. Otherwise, we would use the PKCE extension and hash a generated string. In this case, our secret is gravitational

This exchange happens through a post request that will look something like:

Using the client_secret and code, Okta is able to verify the Teleport client’s request and issues a JSON payload encoded with the bearer token, an expiry time, and perhaps a refresh token. A successful response may look like:

The id_token is issued as a JWT and must be decoded. Given our chosen scopes of openid and email, we can expect the JSON payload to read as:

Step 5

Now that we have obtained the access token, all that is left is to make an API request on behalf of the Teleport user and receive the resources desired. We do this by passing the access token as a Bearer credential in the HTTPS authorization header.

Conclusion

There is a simple beauty to how OIDC works on top of OAuth, given the scale of the problem it solves. However, developers must be extremely careful when designing applications that are compatible with OIDC, as it deals with sensitive and private user information.

Feature image via Pixabay.

At this time, The New Stack does not allow comments directly on this website. We invite all readers who wish to discuss a story to visit us on Twitter or Facebook. We also welcome your news tips and feedback via email: feedback@thenewstack.io.

A newsletter digest of the week’s most important stories & analyses.