OAuth2 in Bridge

What is OAuth2?

OAuth2 is an authorization protocol that allows applications to obtain limited access to user accounts on an HTTP service like google, Facebook or some other Identity Provider (IdP).  The protocol delegates user authentication to the service (IdP) that hosts the user account.  Like SAML, it is a vehicle for authenticating but does not handle the authentication itself.  Instead, it acts as a kind of middleman, coordinating redirects to and out-of-band communication with an IdP, which handles the authentication.  OAuth2 should also be thought of as a loose authorization framework or blueprint.  To that end, OpenID Connect is a specific implementations of OAuth2 that is more convention-driven (JSON and REST) and emphasizes the identity side of the equation.

OAuth2 defines four roles:

  1. Resource owner: the user who authorizes the application to access their account.  Access is limited to an authorization “scope” (e.g., read or write access).
  2. Client: an application (like Bridge Learn) that wants access to a user account.
  3. Resource server: the resource server hosts the protected user accounts.
  4. Authorization server: the authorization server verifies the identity of the user.  The resource and authorization roles are typically combined behind a single API (like Google) so that they act as both the Resource and Authorization server.

Authorization Flow

Bridge supports the authorization code grant type flow, which is optimized for web applications.  The flow involves several steps (described below) and depends on multiple redirects mediated by the user’s web browser.

Step 1: Authorization Request

The authorization code grant flow begins with an HTTP authorization request that may look something like:

https://<idp-domain>/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

client_id, redirect_uri, and response_type are required parameters in the url.  Each parameter is defined below:

client_id: the application’s identifier; it identifies the requesting application to the IdP.

redirect_uri: the callback url to which the service directs the browser after an authorization code is granted.

response_type: the type of authorization the application is requesting.  In this instance code specifies an authorization grant type flow.

scope: specifies the level of access the application is requesting.

state: An opaque value used by the application to maintain state between the request and callback.  The authorization server includes this value when redirecting the user-agent back to the application.  The parameter is used for preventing cross-site request forgery (CSRF).

Step 2: User Authorizes Application

Unless already logged in, the authorization link above directs the user to an IdP login screen where they can authenticate their identity.

Step 3: Application Receives Authorization Code

Once authorized, the IdP redirects the browser to the redirect-uri specified in the application’s authorization request in Step 1.  The redirect url will include an authorization code which should look something like

https://<application-domain>/callback?code=AUTH_CODE

Step 4: Application Requests an Access Token

The application then uses the authorization code, along with the client-id and secret, to make an out-of-band request to the IdP’s token endpoint.

https://<idp-domain>/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL

Step 5: Application Receives the Access Token

If the authorization is valid, the IdP will return a response with access token (and optionally a refresh token) to the application.  The response may look like this:

{
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"email",
  "uid":100101
}

Step 6: Application Receives Profile Information

If the token exchange does not return user profile information (the OpenID Connect implementation of OAuth2, for example, will return profile data), the application can request profile information from a user profile endpoint.

https://<idp-domain>/userinfo

Typically, the access token acquired in the token exchange phase is used as an authorization token in the request header.

Bridge and OAuth2

Bridge’s implementation of OAuth2 is a little more complex than the flow described above because Bridge applications like Learn delegate OAuth2 to a shared authentication service called Authmonger.  Authmonger acts as a kind of middleman, providing a unified api (also OAuth2 but more specifically OpenID Connect, a specific implementation of OAuth2) to any Bridge app that uses it for authentication.  

Behind the scenes, however, it provides a set of growing authentication protocols, including SAML, Google OIDC, and OAuth2, that interact with IdPs to perform client specific authorization. You won’t really need to worry about a Bridge app’s interaction with Authmonger.  Instead, most issues that require troubleshooting will involve Authmonger’s communication with the IdP.

Authmonger stores configuration information for Bridge supported authentication protocols and uses that configuration to manage auth flow for Bridge users when they authenticate.  

For example, if a Bridge client uses an IdP like, say, Google, you would configure authentication for the client on the account “Auth” configuration page like so:

Details about each field are provided below.  Required fields are indicated with an “*”:

Client ID*: the Bridge app identifier that the IdP can use to associate incoming authorization requests with the correct requestor.

Client Secret*: used for the out-of-band token exchange with the IdP after authorization.

Authorize Url*: IdP endpoint used to initiate the authorization request (Step 1)

Token Url*: IdP endpoint used to exchange an authorization code for an access token (Step 4).

Profile Url*: IdP endpoint for accessing user profile information (Step 6).  It is typically accessed as the second of two out-of-band requests after a user has authenticated, and it can require the access token, obtained during the token exchange step.

Scope: A list of space delimited terms that define user access once authorized.  Scope terms are optional and should be specified by the client IdP.  For example, a scope of email profile would return user information like “name”, “nickname”, “updated_at” specific to the profile scope, and “email” and “email_verified” specific to the email scope.  If nothing is entered for this field, a default scope of openid email profile will be applied.  The openid scope returns user information specific to OpenID Connect claims like issuer, subject, audience, and token expiration time.

End Session Endpoint: A url for managing custom client single logout (SLO).  Bridge calls that endpoint when a user logs out of a Bridge session.  This functionality will eventually be deprecated and the “End Session Endpoint” field removed from this admin screen when Authmonger no longer logs users out of their IdP as part of the SLO process.

Login Attribute: An attribute to map an IdP parameter (e.g., id or email) to the Bridge uid field.  Authmonger defaults to id If no attribute specified.

Just In Time Provisioning: Provision the user if they do not already exist as a Bridge user.

Use Access Token As Auth Header: Force Authmonger to use the access token returned in Step 5 as the authorization header in calls to the user profile endpoint to retrieve user data.  This setting is activated by default.

Bridge OAuth2 Flow

When a user visits a Bridge application, Learn, for example, they would be redirected to Authmonger, which would look up the auth configuration information associated with their account (in this case an OAuth2 flow with Google as the IdP) and initiate an auth request by redirecting the user again to Google’s authorization url (Step 1).  There, the user would login (if not already logged in) to authorize Bridge to access their user information (Step 2).  Google would redirect back to Authmonger with an authorization code, which would perform two out-of-band requests to the IdP (Step 3):

  1. It exchanges the authorization code for an auth token via the IdP’s token url (Step 4).  The response includes an access_token (Step 5).
  2. It retrieves the user’s profile information with a request to the IdP’s profile url (Step 6).  The user profile latter request will often require the access_token be used as an authorization token in the request header (e.g., Authorization: Bearer ).  Whether or not the access_token is used as an authorization header is a configuration feature that can be toggled on or off in the SiteAdmin UI.

Finally, Authmonger generates its own user session and tokens if the authorization with the IdP was successful, and it returns them to the Bridge application being authorized.

Additional Requirements and Common Gotchas

  1. The IdP endpoints should use TLS; in other words, the url protocol for authorization, token exchange, and user profile information should be https:///....
  2. If configurable on the IdP, the callback url for Authmonger is https://authmonger-iad-prod.insops.net/oauth2/callback
  3. Ensure the scope params correctly match what the IdP expects.  Failing to do so can lead to an “invalid request” response during Step 3, which will short-circuit the auth cycle.