A guide to OAuth2 and OpenID Connect
Setting-up an OAuth2 app for the first time might seem daunting, but once you understand the flow you'll be easily able to implement single sign-on and OAuth2-based API access for your apps in no time.
TL;DR?
If you're already familiar with OAuth2 and OpenID Connect, then you can simply check out the available URLs and scopes directly from your SSO Tools IdP dashboard to get started.
OAuth2 Overview
OAuth2 allows services to work together to enable single sign-on, or two allow the two services to communicate with each other on a user's behalf. When you choose options like "login with Facebook" or "connect to Stripe", OAuth2 is what is powering the interactions behind the scenes.
Under OAuth2 the user logs-in directly with their identity provider (IdP), and authorizes the IdP to reveal information about them declared in the "scope" (such as a user ID, email address, or even profile information). This information can then be used by the calling service provider ("app") in order to provision the user with an account or to log the user in. The app never sees the username and password used to login and only has access to the information declared in the scope authorized by the user.
Some IDPs may also issue an "access token" during the authentication process. This token can be used for ongoing communication between the two services. For example, the app might use the access token to retrieve or update the user's profile on the IdP, or carry out other actions (such as handling a payment with Stripe).
What is the OpenID Connect part about?
OpenID Connect acts as an extension to OAuth2. Implementations of this standard seem to vary, but the general idea is that the calling app requests an additional "openid" scope from the IdP. If granted, the IdP will issue a special ID token, encoded with useful information about the user, back to the app after a successful authorization is complete.
Under this approach, the app can avoid having to do additional lookups (using the access token) to the IdP in order to retrieve the required user profile information to log the user in.
SSO Tools supports OAuth2 with or without OpenID Connect.
A simplified OAuth2 flow
A user "logging-in" via OAuth2 will cause the following steps to occur.
- The user visits the app (e.g. a website or mobile app). The app shows an option to login via OAuth2 (e.g. "Login with Facebook" or "Login with Your App").
- The user selects this option and is redirected to the IdP (e.g. "Facebook" or "Your App") to authenticate themselves. Usually this would involve logging-in with a username and password. The app includes a list of scopes to ask for in its request.
- After a successful login, the IdP displays the scopes requested by the app, and asks the user to authorize the IdP to provide the requested information or permissions on the user's behalf.
- After authorization, the user is redirected back to the app armed with a special "authorization code".
- The app reads this code and uses this to request a token directly from the IdP.
- The IdP responds with an ID token (if the "openid" scope was requested) and - usually - an access token.
- The app can read the ID token to retrieve user details in order to match or setup an account for the user, and to log the user in. If an access token is also included, the app can use this for ongoing communication with the IdP if required.
Implementing the OAuth2 flow in your app
The following steps describe how to implement OAuth2 SSO in your app using an IdP, such as one provided by SSO Tools.
Step 1: Create an IdP and an app declaration
In SSO Tools, follow the steps to create a new IdP and app (service provider). In this guide we'll assume your IdP's issuer (code) is myidp.
When creating your app, you'll need to provide a "redirect URI". This the place the user will be redirected back to after successful authentication. If you don't know this right away, you can always change it later.
Step 2: Redirect the user to the IdP to authenticate
In your app, create a button or link that redirects the user to the IdP's "authorization URL". In SSO Tools, these take the form of "https://idp.sso.tools/ISSUER/oauth2/authorize", replacing "ISSUER" with the issuer code for your IdP (e.g. "myidp").
Along with this request, you'll have to include some additional query parameters:
client_id: The client ID for the app generated by your IdP (this can be found on the IdP's connected apps page).scope: The space-separated list of requested permissions.redirect_uri: The URL to send the user back to after authentication. This must match the one declared in the app settings on the IdP.response_type: This should just be set to the value "code".
For the scope parameter, SSO Tools currently supports "email" (to allow reading the user's email address), "profile" (to allow reading the user's name and profile information), "openid" (to receive an ID token after authentication), and "offline_access" (to receive a refresh token for long-lived API access).
As such, an example request to redirect the user to on SSO Tools could look like the following:
https://idp.sso.tools/myidp/oauth2/authorize?client_id=abc123&scope=profile%20email%20openid&redirect_uri=https://myapp.com/oauth/callback&response_type=code
Step 3: The user authenticates
Your app can relax for a bit now, since the IdP now takes over in handling the user's authentication and seeking approval for the scopes your app has requested.
Step 4: Receive the user back after authentication
Assuming all went well with the authentication, the IdP will now redirect the user back to your app at the redirect URI you specified. If you don't yet have a route to handle this, then you should create one now and ensure this is registered in the app on SSO Tools and included in your request in Step 2.
When the user arrives back, they'll have a code parameter in their request URL. For example, if your redirect URI is "https://myapp.com/oauth/callback" your app will receive a request at "https://myapp.com/oauth/callback?code=xzy321"
Your app should read this code and make it available for the next step
Step 5: Request a token from the IdP
Next, your app will need to make a request directly to the IdP on its "token" endpoint. On SSO Tools, these endpoints look like "https://idp.sso.tools/ISSUER/oauth2/token". To this endpoint, your app should send an HTTP POST request containing the following data in JSON format:
code: The code received in Step 4.client_id: The client ID (as shown on the connected apps page).client_secret: The client secret (as shown on the connected apps page).redirect_uri: The same redirect URI we used earlier, again.grant_type: This should be set to the value "authorization_code".
For example, given the information above, a sample token request could look like this:
POST https://idp.sso.tools/myidp/oauth2/token
Accept: application/json
Content-Type: application/json
{
"code": "xyz321",
"client_id": "abc123",
"client_secret": "SECRET",
"redirect_uri": "https://myapp.com/oauth/callback",
"grant_type": "authorization_code"
}
Assuming all went well, the response to the request should contain an access_token field (containing a string representing an access token usable against the SSO Tools API for the IdP). If the "openid" scope was requested the response will also include an "id_token" field (containing a string representing a JWT that can be decoded to retrieve the user profile information requested by the scope). If the "offline_access" scope was requested, the response will also include a "refresh_token" field for obtaining new access tokens without re-authentication.
Step 6 (optional): Interact with the IdP's API
Depending on your setup, Step 5 might be the last step needed to complete single sign-on with OAuth2 and OpenID Connect. If your app needs to then communicate with an API for additional data flow (e.g. to power an integration), then read on.
The "access_token" received in Step 5 can now be used against the IdP's API in order to retrieve the user's information. To do so, include the access token in the Authorization header and send off a request to "https://idp.sso.tools/ISSUER/api/users/me".
For example, given the above information, your request could look like this:
GET https://idp.sso.tools/myidp/api/users/me
Accept: application/json
Authorization: ACCESSTOKEN
Assuming all went well, the IdP will respond with information about the current user, as defined in the requested scopes.
Step 7 (optional): Maintain long-lived sessions with refresh tokens
The access token issued in Step 5 is valid for 1 hour. After this, it will no longer be accepted by the IdP's API. If your app needs to maintain access without requiring the user to re-authenticate, you can request a refresh token by including the offline_access scope in your initial authorization request.
When the offline_access scope is included, the token response (Step 5) will also contain a refresh_token field. Refresh tokens are valid for 30 days and can be used to obtain new access tokens without user interaction.
To refresh an access token, make a POST request to the token endpoint with the following data:
client_id: The client ID for your app.client_secret: The client secret for your app.refresh_token: The refresh token received in the previous token response.grant_type: Set to"refresh_token".
For example:
POST https://idp.sso.tools/myidp/oauth2/token
Accept: application/json
Content-Type: application/json
{
"client_id": "abc123",
"client_secret": "SECRET",
"refresh_token": "REFRESH_TOKEN_HERE",
"grant_type": "refresh_token"
}
The response will contain a new access_token (valid for 1 hour) and a new refresh_token (valid for 30 days). You should store the new refresh token for use in your next refresh cycle. Each time you use a refresh token, it is replaced with a new one for security purposes.
Step 8 (optional): Revoke tokens
If your app needs to explicitly invalidate a token (for example, when a user disconnects or logs out of your app), you can revoke it using the revocation endpoint. This will immediately invalidate the token so it can no longer be used to access the IdP's API.
To revoke a token, make a POST request to the revocation endpoint with the token in the request body:
token: The access token or refresh token you want to revoke.
For example:
POST https://idp.sso.tools/myidp/oauth2/revoke
Accept: application/json
Content-Type: application/json
{
"token": "ACCESS_OR_REFRESH_TOKEN_HERE"
}
You can also pass the token in the Authorization header as a Bearer token instead of in the body. The endpoint will respond with an empty JSON object on success. Revoking an access token also invalidates the associated refresh token, and vice versa.