OAuth Implementation

Implement Clever OAuth, understand what SSO tokens can access, and handle login flows from Clever Portal, Instant Login, and Log in with Clever.

Use this page to implement Clever OAuth, understand what SSO tokens can access, and handle login flows from Clever Portal, Instant Login, and Log in with Clever.

Overview

Clever Single Sign-On uses the OAuth 2.0 authorization code grant flow.

In this flow, a user authenticates with Clever, Clever redirects the user back to your application with an authorization code, and your application exchanges that code for an access token. If your app is configured for OIDC, Clever can also return an identity token.

OAuth and OIDC data access

Access tokens

Access tokens acquired through the Clever OAuth flow do not grant full Data API access. They can only access:

  • /me — returns the token type, Clever user ID, and district ID
  • /districts/{id} — where id is the district Clever ID
  • /users/{id} — where id is the user Clever ID

If you need full roster access, use Secure Sync.

Identity tokens

If your application is configured for OIDC, Clever can also return an identity token.

Identity tokens include these claims:

  • user_id — the Clever user ID for API versions before v3.0
  • user_typestudent, teacher, staff, or district admin
  • district — the user’s Clever district ID
  • multi_role_user_id — the Clever user ID for API v3.0 and later
  • email — the user’s email, if available
  • email_verifiedfalse by default; contact Clever Support if you need this claim to be true
  • given_name — the user’s first name
  • family_name — the user’s last name

Identity tokens also include standard metadata claims:

  • iss — always https://clever.com
  • sub — the multi-role Clever user ID used for API v3.0 and later
  • aud — your application client ID
  • iat — the token creation time
  • exp — one hour after token creation
  • nonce — used to prevent CSRF; this must match the nonce value from the original /authorize request when provided
🚧

user_id and multi_role_user_id are different

multi_role_user_id matches sub. Make sure your implementation uses the right identifier for the API version you support.

OAuth flow

Clever expects SSO implementations to use the authorization code grant type.

  1. A user initiates login.
  2. Clever authenticates the user if needed.
  3. Clever redirects the user to your application’s redirect URI with an authorization code.
  4. Your application sends that authorization code to Clever’s token endpoint.
  5. Clever returns an access token and, if configured, an identity token.
  6. Your application uses the access token to identify the user and retrieve the user data it needs.
🚧

Always version your /me request

Call /me with an explicit API version. This ensures you get the correct Clever user ID format for the API version your integration uses.

❗️

State parameters are not included in Clever-initiated logins

Clever-initiated logins that start from the Clever Portal or other Clever-managed entry points do not include a state parameter by default.

If your application requires state, ignore the incoming Clever-initiated login and restart the authentication flow from your own site so you can include state yourself.

For more detail, see https://dev.clever.com/docs/best-practices-edge-cases#state-parameters.

Initiating logins

Users can start Clever SSO in three ways:

  • from the Clever Portal
  • from an Instant Login link
  • from a Log in with Clever button

Your integration should be able to handle all three.

Users may authenticate into Clever through different identity providers set by their district. Your application does not need to handle the district’s identity provider configuration directly.

1444

Screenshot of a Clever login page with multiple identity providers.

SSO from the Clever Portal

Many districts use the Clever Portal as the main launch point for applications. Once your app is certified and connected to a district, users can launch it from their Clever Portal.

When a user clicks your app icon, Clever redirects the user to your primary redirect URI with an authorization code.

2874

Screenshot of the Clever Portal from a teacher's perspective.

You can also review the end-user flow in this Demo Experience.

Typical user flow:

  1. The user opens the district’s Clever login page.
  2. The user selects the correct identity provider for that district.
  3. The user authenticates with that identity provider.
  4. The user reaches the Clever Portal.
  5. The user selects your app icon to start the login flow into your application.

SSO using Instant Login links

Some districts prefer not to use the Clever Portal. To support those districts, Clever provides Instant Login links.

Example Instant Login link:

https://clever.com/oauth/instant-login?client_id=YOUR_CLIENT_ID&district_id=THE_DISTRICT_ID

Typical user flow:

  1. The user clicks an Instant Login link, usually from a district portal, homepage, or bookmark.
  2. The user is taken to the Clever login page unless already authenticated.
  3. The user authenticates if needed.
  4. Clever starts the login flow into your application.

SSO using a Log in with Clever button

If users typically start from your own login page, you can add a Log in with Clever button to your site.

842

Example LIWC button using a Clever button asset

884

Example LIWC button using a Clever icon asset

A Log in with Clever button is a link to https://clever.com/oauth/authorize with parameters that identify your application.

At minimum, include:

  • response_type
  • client_id
  • redirect_uri

Example LIWC URL:

https://clever.com/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Fexample.com&client_id=YOUR_CLIENT_ID

You do not need to include district_id for a general login link on your own site. Clever will use district context already stored in the user’s browser when available.

If district context is not available, the user sees the Clever school picker.

1268

Screenshot of the Clever school picker

🚧

Testing with sandbox districts

You cannot search sandbox districts and schools by name in the school picker. Use the sandbox district_id instead.

If your application has district-specific login pages, you can add district_id to skip the school picker and send users directly to the district login page.

Example:

https://clever.com/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Fexample.com&client_id=YOUR_CLIENT_ID&district_id=YOUR_DISTRICT_ID

LIWC button assets

You can find Log in with Clever assets here.

Authenticating users

Acquire the authorization code

When Clever redirects the user back to your application, the redirect URI includes a code parameter.

Example:

https://primary.redirect?code=code

At this point, your application still does not know who the user is. Your next step is to exchange the code for tokens.

Redirect URI parameters

These are the parameters Clever adds to your redirect URI:

ParameterGuaranteedValue
codeYesAuthorization code generated by Clever
scopeYesScope assigned to your application
stateOnly if provided in the LIWC linkThe same state value your app originally sent

Exchange the code for tokens

To exchange the code, send a POST request to https://clever.com/oauth/tokens.

Use HTTP Basic Authentication with your client ID as the username and your client secret as the password.

Build the Basic Auth header

If your HTTP client supports username/password Basic Auth directly, use your client ID as the username and your client secret as the password.

If you need to build the header yourself:

Authorization: Basic + Base64.encode(client_id + ":" + client_secret)

Supported POST body formats

Clever accepts these content types at /oauth/tokens:

  • application/x-www-form-urlencoded
  • application/json
❗️

Unsupported content types

Clever does not accept other POST body formats such as multipart/form-data. If you see invalid request / invalid content-type errors, make sure you are using one of the supported content types.

The token request body must include:

ParameterExampleDescription
codeheRte321The authorization code received on your redirect URI
grant_typeauthorization_codeAlways authorization_code in this flow
redirect_urihttps://flightschool.edu/oauthThe exact redirect URI where Clever sent the code

Example using application/x-www-form-urlencoded:

POST https://clever.com/oauth/tokens
Authorization: Basic YW5WcFkyVnFkV2xqWldwMWFXTmxDZzpjY1hwWTR0cWRZbGVjNHAxYUdsMXVJ
Content-type: application/x-www-form-urlencoded
Content-length: 107

code=heRte321&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fflightschool.edu%2Foauth

Example using application/json:

POST https://clever.com/oauth/tokens
Authorization: Basic YW5WcFkyVnFkV2xqWldwMWFXTmxDZzpjY1hwWTR0cWRZbGVjNHAxYUdsMXVJ
Content-type: application/json
Content-length: 113

{"code":"heRte321","grant_type":"authorization_code","redirect_uri":"https://flightschool.edu/oauth"}

Token response

Clever returns tokens when:

  • client_id and client_secret are valid
  • redirect_uri exactly matches the URI where Clever sent the code
  • code is valid
🚧

Authorization codes expire quickly

Authorization codes are valid for one minute and can only be exchanged once.

Example response (id_token is only present when your app is configured for OIDC):

{
  "access_token": "access_token_here",
  "id_token": "id_token_here"
}
❗️

Token expiration

Tokens expire after 24 hours and cannot be refreshed. Do not use them for long-term user identification.

Clever user sessions expire after 2 hours.

Use the returned tokens

Access tokens

After you receive an access token, call https://api.clever.com/v3.0/me to retrieve the user’s Clever ID, district ID, and token type.

In most implementations, you should identify the token owner immediately after exchange.

Identity tokens

If your app receives an identity token, decode and verify it using a JWT library rather than parsing it manually.

A list of language-specific JWT libraries is available at jwt.io/libraries.

Bearer tokens

Use the access token as a bearer token in the Authorization header:

GET https://api.clever.com/some_clever_resource
Authorization: Bearer jsfUI2131da2f

The authorized_by field

Districts must authorize Clever Single Sign-On connections before users can log in with them. Districts do this by connecting to your app at the district level and configuring sharing permissions.

To learn more:

You can identify a district-authorized SSO request by looking at the /me response. In a Clever Single Sign-On flow, authorized_by is set to district.

{
  "type": "user",
  "data": {
    "id": "5fc43758db087d0be186c29d",
    "district": "5d0a9e5d0958b300014e49d2",
    "type": "user",
    "authorized_by": "district"
  },
  "links": [
    {
      "rel": "self",
      "uri": "/me"
    },
    {
      "rel": "canonical",
      "uri": "/v3.0/users/5fc43758db087d0be186c29d"
    },
    {
      "rel": "district",
      "uri": "/v3.0/districts/5d0a9e5d0958b300014e49d2"
    }
  ]
}