Authentication
Learn how to add authentication to a content extension.
If an authentication-enabled app has a content extension, users of the app must authenticate with a third-party platform before they can access the app's content.
This topic explains how to implement authentication in a content extension.

Step 1: Enable authentication

By default, authentication is disabled.
To enable authentication:
  1. 1.
    Navigate to an app via the Developer Portal.
  2. 2.
    Click Authentication.
  3. 3.
    Enable This app requires authentication.
The Authentication page has two fields:
  • Redirect URL
  • Authentication base URL
The purpose of these fields is explained in the following steps.

Step 2: Check if the user is authenticated

When a user opens a content extension, Canva sends a POST request to the following endpoint:
1
<base_url>/content/resources/find
Copied!
The body of this request includes a user property that contains the ID of the user. Your extension can use this ID to check if the current user is associated with a user in the backend of a third-party platform.
If the ID of the Canva user is not associated with a user of the third-party platform, respond to the request with the following object:
1
{
2
"type": "ERROR",
3
"errorCode": "CONFIGURATION_REQUIRED"
4
}
Copied!
This tells Canva to render a Connect button. Users can select the button to begin the authentication flow.
The user's ID is obfuscated and unique to each app. If an app has multiple extensions, each extension will receive the same ID for a user, but different apps will receive different IDs for the same user.
If the ID of the Canva user is associated with a user of the third-party platform, respond with the content that Canva should render in the side panel:
1
{
2
"type": "SUCCESS",
3
"resources": []
4
}
Copied!
Typically, this content will belong to the authenticated user.
Canva includes the ID of the user's team in all requests, via the brand property. You can use this ID to add team-specific features to an extension.

Step 3: Redirect users to the Redirect URL

When a user clicks the Connect button, Canva opens a pop-up window.
Inside this window, Canva redirects the user to the app's Redirect URL.
The Redirect URL must point to a page that lets users authenticate with the third-party platform. For example, this could be a login form with a username and password, or the start of an OAuth 2.0 authorization flow. The exact authentication method is the responsibility of the app. Canva doesn't enforce any specific approach.
When redirecting users to the Redirect URL, Canva automatically appends a number of query parameters to the URL. All of these parameters serve a purpose, but the user and state parameters are of particular importance.
The user parameter contains the ID of the user. If the user successfully authenticates, the app needs to persist this ID to a datastore. When the user returns to the app, the app can use this ID to check if the user is authenticated or not.
The state parameter contains a unique token for the authentication flow. For security reasons, the app must return this token to Canva at the end of the authentication flow. This protects the app against cross-site request forgery (CSRF) attacks.
To see the complete list of query parameters, see Redirect URL.

Step 4: Verify the request signature

The redirection from Canva to the Redirect URL is a GET request. Before you can submit an app for review, you must implement signature verification for this request. This prevents third-parties from sending requests to the URL.
To learn how to set up signature verification for a GET request, see Verifying GET requests.

Step 5: Redirect the user back to Canva

At the end of the authentication flow, redirect users to the following URL from within the pop-up window:
1
https://canva.com/apps/configured?success=<true|false>&state=<token>
Copied!
This must be a 302 redirect.
You also need to append the following parameters to the URL:
  • success
  • state
If the user has successfully authenticated, set the success parameter to true. This tells Canva to close the pop-up window and reload the extension. When the extension reloads, it can once again check if the user is authenticated.
If the user has not successfully authenticated, set the success parameter to false. This tells Canva to close the pop-up window without reloading the extension.
Always set the state parameter to the value of the token that Canva provided at the start of the authentication flow. If the state parameter is missing or invalid, an error occurs and the authentication fails.
Canva's state parameter is distinct from OAuth 2.0's state parameter.

Step 6: Let users disconnect from Canva

After a user authenticates, they have the option of revoking that authentication. Your app must support this option to be eligible for distribution via the Apps Directory.
When a user disconnects an app, Canva sends a POST request to the following endpoint:
1
<authentication_base_url>/configuration/delete
Copied!
<authentication_base_url> is a placeholder that refers to the app's Authentication base URL field, which can be set via the Authentication page in the Developer Portal.
Canva automatically appends the /configuration/delete path to the URL. Don't include the path in the Authentication base URL field.
The body of this request includes a user property, which contains the ID of the user. Your app can use this ID to remove the association between the Canva user and the user in the backend of the third-party platform.
To learn more about this endpoint, see the API reference

Example

This example uses ESM modules, which means it uses the import keyword instead of the require keyword. To run the example, add 'type': 'module' to the package.json file.
1
import basicAuth from "express-basic-auth";
2
import express from "express";
3
import querystring from "querystring";
4
import { Low, JSONFile } from "lowdb";
5
6
const app = express();
7
8
app.use(express.json());
9
app.use(express.static("public"));
10
11
// Set up the database
12
// Docs: https://github.com/typicode/lowdb
13
const adapter = new JSONFile("db.json");
14
const db = new Low(adapter);
15
await db.read();
16
db.data ||= { loggedInUsers: [] };
17
18
// Set up Redirect URL
19
app.get(
20
"/login",
21
basicAuth({
22
users: { admin: "password123" },
23
challenge: true,
24
}),
25
async (request, response) => {
26
const { loggedInUsers } = db.data;
27
const { user } = request.query;
28
29
// Add the user to the database
30
if (!loggedInUsers.includes(user)) {
31
loggedInUsers.push(user);
32
await db.write();
33
}
34
35
// Construct query parameters for redirect back to Canva
36
const params = querystring.stringify({
37
success: true,
38
state: request.query.state,
39
});
40
41
// Redirect back to Canva
42
response.redirect(302, `https://canva.com/apps/configured?${params}`);
43
}
44
);
45
46
// Handle requests for content
47
app.post("/content/resources/find", async (request, response) => {
48
const { loggedInUsers } = db.data;
49
const { user } = request.body;
50
51
// The user is logged-in
52
if (loggedInUsers.includes(user)) {
53
response.send({
54
type: "SUCCESS",
55
resources: [
56
{
57
type: "IMAGE",
58
id: "123456",
59
name: "Leaning Tower of Pisa",
60
thumbnail: {
61
url: "https://picsum.photos/id/629/600",
62
},
63
url: "https://picsum.photos/id/629/2000",
64
contentType: "image/jpeg",
65
},
66
],
67
});
68
return;
69
}
70
71
// The user is not logged-in
72
response.send({
73
type: "ERROR",
74
errorCode: "CONFIGURATION_REQUIRED",
75
});
76
});
77
78
// Handle disconnection requests
79
app.post("/configuration/delete", async (request, response) => {
80
// Remove the current user from the database
81
db.data.loggedInUsers = db.data.loggedInUsers.filter((user) => {
82
return user !== request.body.user;
83
});
84
await db.write();
85
86
response.send({
87
type: "SUCCESS",
88
});
89
});
90
91
app.listen(process.env.PORT || 3000);
Copied!
Last modified 27d ago