Thinkific uses the OAuth 2.0 authorization framework to issue access tokens on behalf of Thinkific Sites.
A detailed explanation of the OAuth options and steps is provided below. For a quick overview of the endpoints refer to our OAuth API Reference.
In this article:
Overview
When building Apps, you must authorize users using the Authorization Code Flow shown below. This flow can be extended with PKCE (Proof Key for Code Exchange) for scenarios where Client Secret cannot be safely stored.
Note: This flow only supports authorization to access Thinkific API's on behalf of a Thinkific Site. To identify the current user and access their profile data, the flow should be extended with OpenID Connect.
App Credentials
In order to use this your App, you will need the app credentials (Client ID and Client Secret). You can collect these by registering an app with Thinkific.
See Building Apps in Thinkific to learn more.
Users
During Authorization, User Roles help to determine whether the user is permitted to install and access an App's functionality.
Installing Apps
Only users that have the role of Site Owners, Site Admins, or Partners will be able to install an App.
User flow
Your app must follow the correct installation flow, so that end users have a consistent app installation experience. This flow is detailed here: What should a user see when they install my app?
After Installation on a Thinkfic Site
Once an App has been installed on a Thinkific Site, users of all roles (including students) will be granted an access token when going through the OAuth Flow.
The issued access token is scoped to the user's appropriate role. For example, if the user is a student, their access token will return an unauthorized error when making requests to any of the Admin APIs, however they will be able to make successful calls to the Teaching API which returns data scoped to their role.
Before authorizing a user to access your app
When building an app, you should confirm the user's level of access before granting access to your App's Admin tools.
To do so, once you receive an access token from an OAuth flow, you should make a call to the Admin API using the Access Token granted to that user (to something like /api/public/v1/users
). If the user is an admin they will receive a successful response, if they are a student they will receive an unauthorized response and should not be granted access.
You can gain more contextual information about a user by using OpenID Connect.
Authorization Code Flow
The authorization code flow returns a refresh token that can require the user to grant access once.
Step 1: Ask for permissions from the Thinkific Site Owner
In order to gain the necessary permissions for a Thinkific site, you'll need to redirect the Site Owner to the authorization flow by constructing the following URL:
https://{subdomain}.thinkific.com/oauth2/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_mode=query&response_type=code&state={state}
where:
Value | Description |
subdomain: | The Subdomain for the Thinkific Site where the app will be installed. |
client_id | Your App's client ID. (Retrieved in Step 1). |
redirect_uri | One of the authorized redirect URIs you've configured in your App. (Completion of this authorization will redirect back to this uri) |
state | A unique and non-guessable value which will be sent back to the authorization code request. (Optional, but highly recommended to mitigate CSRF attacks) |
response_type | When using Authorization code flow, this value should always be code. |
response_mode | When using Authorization code flow, the default value, if blank is "query" but "form_post" can also be used |
Note: Only the Site Owner can complete this authorization, Course & Site Admins are not able to grant access to apps.
Step 2: Confirm authorization code
Once the Site Owner grants access by installing the app, Thinkific will redirect the user back to the informed redirect_uri using the following format:
{redirect_uri}?code={authorization_code}&subdomain={subdomain}&state={state}
where:
Value | Description |
authorization_code | A randomly generated code that expires in 60 seconds |
subdomain | The Subdomain for the Thinkific Site where the app is being installed. |
state | The value (if any) provided in the previous request using the state value. |
The app should receive Thinkific's request and then make the final request to retrieve the access token using the authorization code.
Step 3: Retrieving access token
Upon receiving the authorization code, the app should perform one last request to retrieve the access token, a POST request using basic authentication.
Endpoint:
POST https://{subdomain}.thinkific.com/oauth2/token
Basic Authentication:
Basic Authentication can be generated by encoding a username and a password in base64.
If using a tool that handles encoding for you (like Postman), input the username and password with the following values.
Key | Value | Description |
Username | client | Your app's client ID |
Password | client_secret | Your apps's client secret |
When encoding authentication in base64 manually, use the folowing format:
base64(client_id:client_secret)
The resulting example should be something like:
Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=
Request parameters:
In the body of the request, two values are expected:
Value | Description |
grant_type | Value should be authorization_code |
code | The authorization code provided in the previous step |
Example:
{
"grant_type": "authorization_code",
"code": "5a3c34512703ee80eb006dd255c0345a"
}
Response parameters:
Upon receipt of a successful request, Thinkific will respond with a HTTP status 200
with the following attributes:
Value | Description |
access_token | An access token to make secure requests. This token expires after 24 hours. |
refresh_token | A refresh token to request a new access token. Refresh tokens do not expire but can only be used once. |
token_type | Value should be "bearer" |
gid | Global id to uniquely identify a Thinkific Site |
expires_in | Number of seconds until the access_token will become invalid. |
Example:
{
"access_token": "5a16505d-5ee5-4853-8cb9-41b63a13a291",
"token_type": "bearer",
"refresh_token": "3cb103dd-f05f-43a9-aa51-c33b8f1f2546",
"expires_in": 86399,
"gid": "703ca109-741c-40d2-9cf0-3ac51c63086b"
}
Errors
Invalid Credentials
If the client_id or client_secret are invalid, Thinkific will respond with a HTTP 401 Status:
{
"error": "invalid credentials"
}
Invalid Code
If the authorization code is incorrect or no longer valid, Thinkific will respond with a HTTP 401 status:
{
"error": "invalid code"
}
Step 4: Making secure requests
Now that you have a valid access token, you can begin making authorized requests to Thinkific's APIs using Bearer Token Authorization.
Example Request:
curl -H 'Authorization: Bearer 386ea500-fc01-45e9-8914-f53e3b7c0ed5' \
-H 'Content-Type: application/json' \
https://api.thinkific.com/api/public/v1/users
Step 5: Refreshing token
Access tokens expire after 24 hours, and will need to be refreshed in order to continue accessing the Thinkific API.
Apps can use the refresh_token that is provided when it received the current access token to request a new valid access token with the following API call:
Endpoint:
POST https://{subdomain}.thinkific.com/oauth2/token
Once again, this endpoint uses the Basic Authorization method, so be sure to follow this structure.
Request parameters:
While the first time the request parameters included a "code" value, during the refresh call we will insted now pass a grant_type of refresh_token
.
Value | Description |
grant_type | Value should be "refresh_token" |
refresh_token | Refresh token to request a new access token |
example:
{
"grant_type": "refresh_token",
"refresh_token": "0d8dcc00-a6e7-450c-baef-6f27bb07e36c"
}
Response parameters:
Upon successful refresh of the access_token, Thinkific will respond with a HTTP status 200
with the following attributes:
Value | Description |
access_token | A new access token to make secure requests. |
refresh_token | A refresh token to request a new access token. Refresh tokens do not expire but can only be used once. |
token_type | Value should be "bearer" |
gid | Global id to uniquely identify a Thinkific Site |
expires_in | Number of seconds until the access_token will become invalid |
example:
{
"access_token": "4a6cb9f1-3b1a-449f-bf57-5ec5db7272b8",
"token_type": "bearer",
"refresh_token": "e1963268-7687-4c69-a7c9-96957dca4550",
"expires_in": 86399,
"gid": "703ca109-741c-40d2-9cf0-3ac51c63086b"
}
Errors
Invalid Credentials
If the client_id or client_secret are invalid, Thinkific will respond with a HTTP 401 Status:
{
"error": "invalid credentials"
}
Invalid Refresh Token
If the refresh token is incorrect or no longer valid, Thinkific will respond with a HTTP 401 status:
{
"error": "invalid refresh token"
}
Note: Every time an access_token is generated, a new refresh token is also generated and the previous token is invalided.
Authorization Code Flow with PKCE
Proof Key for Code Exchange or just PKCE, is an extension to the Authorization Code flow that helps to prevent certain attacks and to be able to securely perform the OAuth exchange from an App. It is a best practice for Apps that cannot store the Client Secret, since it's replaced by a one time code challenge.
Looking for a quickstart? Follow this link for a detailed starter using Vue.JS
Step 1: Generate code verifier, code challenge method and code challenge
The code verifier and code challenge should be generated by the App for the OAuth requests.
Value | Description |
code_verifier | A dynamically created cryptographically random key and it should be unique for every authorization request. |
code_challenge_method | Is used to generate the code challenge, "S256" is the standard at Thinkific. |
code_challenge | Is a hashed version of the code verifier, using the code challenge method algorithm and base64url-encoded. |
Step 2: Ask for permissions from the Thinkific Site Owner with code challenge and code challenge method
In order to gain the necessary permissions for a Thinkific site, you'll need to redirect the Site Owner to the authorization flow by constructing the following URL.
Code Verifier and Code Challenge
Prior to requesting access, you must generate the code verifier. It's recommended the code verifier to be a string with the size of 43-128 characters.
From the code verifier, you must hash using SHA 256 and encode to a Base 64 URL safe string.
Requesting Access
https://{subdomain}.thinkific.com/oauth2/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_mode=query&response_type=code&state={state}&code_challenge={code_challenge}&code_challenge_method={code_challenge_method}
where:
Value | Description |
subdomain: | The Subdomain for the Thinkific Site where the app will be installed. |
client_id | Your App's client ID. (Retrieved in Step 1). |
redirect_uri | One of the authorized redirect URIs you've configured in your App. (Completion of this authorization will redirect back to this uri) |
state | A unique and non-guessable value which will be sent back to the authorization code request. (Optional, but highly recommended to mitigate CSRF attacks) |
response_type | When using Authorization code flow, this value should always be code |
response_mode | When using Authorization code flow, the default value, if blank is "query" but "form_post" can also be used |
code_challenge | A challenge derived from the code verifier, using SHA 256 and encoded to a Base 64 URL safe string. |
code_challenge_method | This is the algorithm used to generate the code_challenge. This value should always be "S256" |
Note: Only the Site Owner can complete this authorization, Course & Site Admins are not able to grant access to apps.
Step 3: Confirm authorization code
Once the Site Owner grants access by installing the app, Thinkific will redirect the user back to the informed redirect_uri using the following format:
{redirect_uri}?code={authorization_code}&subdomain={subdomain}&state={state}
where:
Value | Description |
authorization_code | A randomly generated code that expires in 60 seconds |
subdomain | The Subdomain for the Thinkific Site where the app is being installed. |
state | The value (if any) provided in the previous request using the state value. |
The app should be prepared to receive Thinkific's request and then make the final request to retrieve the access token as described in the next step.
Step 4: Retrieving access token
Upon receiving the authorization code, the app should perform the token request to retrieve the access token.
Endpoint:
POST https://{subdomain}.thinkific.com/oauth2/token
Basic Authentication:
The token request should be authenticated by using the Basic Authentication method, using the Client ID and Client Secret encoded in base64.
Please note that Client Secret is optional for the Authorization Code with PKCE, but it's required if you want to receive the refresh token.
If using a tool that handles encoding for you (like Postman), input the username and password with the following values.
Key | Value | Description |
Username | client | Your app's client ID |
Password | client_secret | Your apps's client secret |
base64(client_id:client_secret)
The resulting example should be something like:
Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=
Request parameters:
In the body of the request, two values are expected:
Value | Description |
grant_type | This value should be "authorization_code" |
code | The authorization code provided in the previous step |
code_verifier | The random key generated at the beginning of the flow |
Example:
{
"grant_type": "authorization_code",
"code": "5a3c34512703ee80eb006dd255c0345a",
"code_verifier": "l2sdelBTs0cQiUJH-kjVxaxCv994o7gvqATmrGlru78"
}
Response parameters:
Upon receipt of a successful request(code verifier validated with the code challenge), Thinkific will respond with a HTTP status 200
with the following attributes:
Value | Description |
access_token | An access token to make secure requests. This token expires after 24 hours |
token_type | Value should be "bearer" |
gid | The Subdomain for the Thinkific Site where the app is being installed. |
expires_in | Number of seconds until the access_token will become invalid. |
refresh_token | A refresh token to request a new access token. Refresh tokens do not expire but can only be used once. Only returned if Client Secret is provided |
Example:
{
"access_token": "5a16505d-5ee5-4853-8cb9-41b63a13a291",
"token_type": "bearer",
"refresh_token": "3cb103dd-f05f-43a9-aa51-c33b8f1f2546",
"expires_in": 86399,
"gid": "703ca109-741c-40d2-9cf0-3ac51c63086b"
}
Errors
Invalid Credentials
If the client_id or client_secret are invalid, Thinkific will respond with a HTTP 401 Status:
{
"error": "invalid credentials"
}
Invalid Grant
If the code challenge method is not S256 or if the code verifier and code challenge validation fails, Thinkific will respond with a HTTP 401 status:
{
"error": "invalid grant"
}
Invalid Code
If the authorization code is incorrect or no longer valid, Thinkific will respond with a HTTP 401 status:
{
"error": "invalid code"
}
Step 5: Making secure requests
Now that you have a valid access token, you can begin making authorized requests to Thinkific's APIs using Bearer Token Authorization.
Example Request:
curl -H 'Authorization: Bearer 386ea500-fc01-45e9-8914-f53e3b7c0ed5' \
-H 'Content-Type: application/json' \
https://api.thinkific.com/api/public/v1/users
You can find more information about the OAuth process in our free app development course!