API Integration Guide: OAuth 2.0 & Canvas LMS
The OAuth 2.0 protocol provides a secure mechanism for a third-party application (the Client) to access user information stored in Canvas LMS without requiring the user to share their Canvas credentials directly.
When an instructor links their account with a third-party application, they are redirected to the Canvas SSO login page. Upon successful authentication and consent, the application is granted authorized access to the instructor’s Canvas data. This linked state enables core integrations, such as importing student rosters and exporting grades seamlessly.
Terminology Reference
Section titled “Terminology Reference”Understanding OAuth 2.0 requires defining the specific roles each system component plays:
- Resource Owner: The end-user (e.g., the instructor) who grants access to their data.
- Client: Your application requesting access to the user’s information.
- Authorization Server: The system that authenticates the user and issues access tokens. Canvas LMS acts as the authorization server.
- Authorization Grant: A credential representing the resource owner’s consent. The client exchanges this grant with the authorization server for an access token.
- Access Token (Bearer Token): The secure key used by the client to access protected resources.
- Resource Server: The system hosting the protected user accounts and information. It verifies the access token before responding to requests.
- Redirect URI: The pre-registered destination where the authorization server sends the user after granting consent.
- Scope: The specific permissions granted by the end-user (e.g., reading course lists, fetching enrollments).
- Client ID & Client Secret: The unique credentials used to identify and authenticate your application to the authorization server.
Authorization Code Flow
Section titled “Authorization Code Flow”Canvas LMS implements the Authorization Code Flow, which is the most common and secure OAuth 2.0 flow for server-side applications. The process is divided into front-channel (browser-based) and back-channel (server-to-server) communications.
Sequence Diagram
Section titled “Sequence Diagram”sequenceDiagram
participant User as Resource Owner (Instructor)
participant Client as Client Application
participant AuthServer as Authorization Server (Canvas)
participant ResourceServer as Resource Server (Canvas)
Note over User, AuthServer: Front-Channel Flow
User->>Client: Initiates account linking
Client->>User: Redirects to Canvas Authorization URL
User->>AuthServer: Enters credentials & grants consent
AuthServer->>User: Redirects to Client Redirect URI with Auth Code
User->>Client: Passes Auth Code via Redirect
Note over Client, ResourceServer: Back-Channel Flow
Client->>AuthServer: POST Auth Code, Client ID, Client Secret
AuthServer-->>Client: Returns Access Token & Refresh Token
Client->>ResourceServer: API Request + Access Token
ResourceServer-->>Client: Returns Requested Data
1. Requesting User Consent (Front-Channel)
Section titled “1. Requesting User Consent (Front-Channel)”To begin the flow, your application redirects the user’s browser to the Canvas authorization endpoint:
GET https://<canvas-instance>/login/oauth2/auth
Include the following query parameters:
client_id: Your application’s unique ID.response_type: Set tocode.redirect_uri: The endpoint in your application that will handle the callback.scope: (Optional) A space-separated list of required scopes.
The user logs into Canvas and is prompted to authorize the application. Upon consent, Canvas redirects the user back to the redirect_uri, appending a temporary authorization code to the URL query string (?code=...).
2. Exchanging the Code for a Token (Back-Channel)
Section titled “2. Exchanging the Code for a Token (Back-Channel)”Your application extracts the authorization code and securely sends a background POST request to the Canvas token endpoint:
POST https://<canvas-instance>/login/oauth2/token
Include the following JSON payload or form data:
grant_type: Set toauthorization_code.client_id: Your application’s unique ID.client_secret: Your application’s secure secret key.redirect_uri: Must exactly match the URI used in step 1.code: The authorization code received from the redirect.
Canvas validates the credentials and returns a JSON response containing the access_token, a refresh_token, and the expires_in duration (typically 3600 seconds).
3. Making Authenticated API Requests
Section titled “3. Making Authenticated API Requests”Your application stores these tokens securely and utilizes the access_token in the Authorization header of subsequent API requests to the Canvas Resource Server.
GET /api/v1/courses HTTP/1.1Host: <canvas-instance>Authorization: Bearer <access_token>4. Refreshing Expired Tokens
Section titled “4. Refreshing Expired Tokens”Access tokens possess a limited lifespan. Before making API calls, your application should validate the token’s temporal validity. If the token is expired, issue a refresh request to the token endpoint:
POST https://<canvas-instance>/login/oauth2/token
Include the following payload:
grant_type: Set torefresh_token.client_id: Your application’s unique ID.client_secret: Your application’s secure secret key.refresh_token: The refresh token received in step 2.
Upon success, the new access_token and updated expiration timestamp should be persisted to your database.
Spring Boot Implementation Example
Section titled “Spring Boot Implementation Example”To demonstrate this within a Java environment, the following snippet illustrates a basic Spring Boot service handling the back-channel token exchange using Spring’s RestTemplate.
package com.example.canvasintegration;
import org.springframework.beans.factory.annotation.Value;import org.springframework.http.*;import org.springframework.stereotype.Service;import org.springframework.util.LinkedMultiValueMap;import org.springframework.util.MultiValueMap;import org.springframework.web.client.RestTemplate;
@Servicepublic class CanvasOAuthService {
@Value("${canvas.client-id}") private String clientId;
@Value("${canvas.client-secret}") private String clientSecret;
@Value("${canvas.redirect-uri}") private String redirectUri;
private final RestTemplate restTemplate = new RestTemplate();
/** * Exchanges the front-channel authorization code for a Canvas access token. */ public CanvasTokenResponse exchangeCodeForToken(String code) { String tokenUrl = "https://canvas.instructure.com/login/oauth2/token";
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("grant_type", "authorization_code"); map.add("client_id", clientId); map.add("client_secret", clientSecret); map.add("redirect_uri", redirectUri); map.add("code", code);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
// Perform the POST request to the Authorization Server return restTemplate.postForObject(tokenUrl, request, CanvasTokenResponse.class); }}This service can then be injected into your web controllers to handle the callback endpoint where the user is redirected after granting consent.