Example SSO Application

Walking through the Clever SSO flow using an example Python application

In this guide, we'll look at a sample Python app called SquidWord and how it implements Clever SSO. For a general overview of SSO, check out our guide to SSO

SquidWord is hosted on Heroku - you can see the app at https://squidword.herokuapp.com/ - the code for SquidWord can be found here: https://github.com/mlezeng/squidword. This application makes use of the web, os and requests libraries.

The sandbox district contains the same data as the default sandbox, so you can use any of those credentials to log in. For example:

  • Student: 310100 / 310100
  • Teacher: 092643 / 092643
  • If you're logging with the "Log in with Clever" button on the main page, search 53ee4b8a44abc88c1c00119b in the school picker to reach the district login page.

You can also connect your sandbox account to Squidword by clicking its signup URL: https://clever.com/signup/squidword-dev and log in as users from your sandbox district.

Next, we'll walk through all the steps SquidWord takes to authenticate a user.

Defining the Redirect URI & Key Variables

On line 7 & 13 of bin/app.py, we've defined the redirect URI - this must match at least one of the redirect URIs you've listed in your app's OAuth Settings.

The class that dictates the actions taken on this page (IL) starts on line 137 of bin/app.py.

You'll also notice SquidWord's Client ID and Client Secret (which can be found in the OAuth Settings page in your Clever Dashboard) - are stored as environment variables and are called using os (lines 11-12)

Acquiring the Code

When a user loads SquidWord's redirect URI, we expect them to have been redirected there by Clever. When they are redirected, the URI in the user's browser should look something like this: https://squidword.herokuapp.com/oauth/clever/?code=5e87ec5070ac5ce87da97daac069a82f6c95818d&scope=read%3Auser_id%20read%3Adistrict_admins%20read%3Aschool_admins%20read%3Asis

SquidWord uses web.input to grab the code and scope params, setting the value to None if these params are not present. If these are not present, it shows the Index page instead (which includes a Log in with Clever button) so the user can initiate a login via Clever.

Exchanging the Code for a Token

getToken(code) is called from line 155 - this POSTs to https://clever.com/oauth/tokens with the aquired code, my redirect_uri, and the grant_type, which is authorization code. The POST uses basic authorization based on SquidWord's client_id and client_secret.

As long as the following conditions are met:

  • code is valid
  • redirect_uri matches the redirecrt URI where the app received the code
  • client_id and client_secret are valid

Clever should respond with a token. getToken extracts the token from the response and returns it to IL.

Using the Token

Once the token is acquired,IL uses that token to GET the https://api.clever.com/me endpoint - this endpoint should return the user's Clever id, district ID, and user type.

Creating a User

IL then attempts to create a new User with this information. class User's: __new__ function uses the same IL bearer token against the /types/id endpoint to get the user's name, and returns the User object.

🚧

First and last name will always be present, but middle name may not. Because of this, the __new__ function must first check to see if that field exists in the API response.

IL will then show the user a home page, which displays the first name and user type pulled from the User object (and a great squid gif).