Authentication

Learn how to add authentication to an app.

You can configure apps to support authentication. If an app supports authentication, users must authenticate with a third-party platform before they can access the app's extensions.

For example, apps with publish extensions may support authentication to ensure that only users with accounts on the destination platform can publish their designs, while apps with content extensions may support authentication to allow users to access private media (e.g. images uploaded to their Dropbox account).

To see examples of the authentication flow, check out the following apps:

Authentication can only be enabled for the entire app, not for individual extensions. This ensures that, if the app has multiple extensions, users only have to authenticate once for the entire app — not for each individual extension.

You can't require users to authenticate before accessing an editing extension.

Step 1: Enable authentication

  1. Navigate to an app via the Developer Portal.

  2. Select Authentication.

  3. Enable This app requires authentication.

The Authentication page has two fields:

  • Redirect URL

  • Authentication base URL

The form doesn't save unless both fields have a value. The expected values of these fields are explained throughout this tutorial.

Step 2: Check if the user is authenticated

When a user opens an extension, Canva provides the extension with the ID of the user. This ID allows your app to identify unique users.

Extensions need to check if the user's ID is associated with a user in the platform's backend. If it is, the extension continues to load. If it's not, the extension can render a UI that allows the user to start the authentication flow.

The implementation details depend on the app's extensions.

Content extensions

When a user opens a content extension, Canva sends a POST request to the following endpoint:

<base_url>/content/resources/find

The <base_url> placeholder refers to extension's Base URL field, which you can set in the Developer Portal, via the app's Extensions page.

Canva provides the ID of the user in the body of the request, via the user property. The extension can check if the ID is associated with a user in their backend, which indicates if they're authenticated or not.

If this endpoint responds with a "CONFIGURATION_REQUIRED" error, Canva renders a Connect button:

{
"type": "ERROR",
"errorCode": "CONFIGURATION_REQUIRED"
}

If the extension responds with content, Canva assumes the user is authenticated.

To learn more about the /content/resources/find endpoint, refer to the API reference.

Publish extensions

When a user opens a publish extension in an authentication-enabled app, Canva sends a POST request to the following endpoint:

<authentication_base_url>/configuration

The <authentication_base_url> placeholder refers to the app's Authentication base URL field, which you can set in the Developer Portal, via the app's Authentication page. Canva appends a value of /configuration to this endpoint, so /configuration must be omitted from the Authentication base URL field.

Canva provides the ID of the user in the body of the request, via the user property. The extension can check if the ID is associated with a user in their backend, which indicates if they're authenticated or not.

If this endpoint responds with a "CONFIGURATION_REQUIRED" error, Canva renders a Connect button:

{
"type": "ERROR",
"errorCode": "CONFIGURATION_REQUIRED"
}

If this endpoint responds with a "SUCCESS" response, Canva continues loading the extension:

{
"type": "SUCCESS",
"labels": ["PUBLISH"]
}

To learn more about the /configuration endpoint, refer to the API reference.

Step 3: Redirect users to the Redirect URL

When a user clicks the Connect button, Canva opens a pop-up window and, inside this window, redirects the user to the app's Redirect URL. You can set the app's Redirect URL via the app's Authentication page.

The Redirect URL should point to a page that allows the user to authenticate. This page could contain:

  • A login form with a username and password field.

  • The start of an OAuth 2.0 authorization flow.

  • A QR code the user can scan with their phone.

…or some other option that allows the user to authenticate.

Canva appends a number of query parameters to the Redirect URL. For a complete list of query parameters, refer to the API reference.

All of the query 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 data store. Then, when the user returns to the app, the app can check if the user is authenticated or not.

The state parameter is a unique ID that's generated for each authentication flow. This ID must be returned to Canva at the end of the flow. This is a security measure to protect the app against Cross-site request forgery (CSRF) attacks.

You must not send marketing emails to Canva users who sign up for your platform during the authentication flow unless they explicitly opt-in.

Step 4: Verify the request signature

The redirection to an app's Redirect URL is a GET request. Before you can submit an app for review, your app must verify that this request is actually sent from Canva (and not from some nefarious third-party). The values of the query parameters are required to verify the request.

To learn more, refer to Verifying GET requests.

Step 5: Redirect users back to Canva

When the user has finished authenticating, the app must perform a 302 redirect to the following URL from within the pop-up window:

https://canva.com/apps/configured?success=true&state=<state_goes_here>

If you're creating an app for canva.cn, replace canva.com with canva.cn.

You must append the following query parameters to this URL:

  • success

  • state

If the user has successfully authenticated, the success parameter must be true.

The state parameter must contain the value of the state parameter that Canva provided at the start of the authentication flow.

After the redirection, Canva closes the pop-up window and reloads the extension. This allows the extension to (once again) check if the user is authenticated.

If you set the success parameter to false, Canva closes the pop-up window and doesn't reload the extension. This means the Connect button remains visible.

To learn more about this endpoint, refer to the API reference.

OAuth 2.0

If your app uses OAuth 2.0 for authentication, it's important to understand that OAuth 2.0 has its own concept of a state parameter. This parameter is also used to protect an app against CSRF attacks, but it's distinct from the state parameter that Canva provides.

If your app lets users authenticate via OAuth 2.0, it must handle two state parameters:

  • The state parameter from Canva.

  • The state parameter from the OAuth 2.0 provider.

Only the state parameter from Canva should be passed back to Canva. To learn how to handle the state parameter from the OAuth 2.0 provider, refer to the provider's documentation.

To learn more about OAuth 2.0 in general, refer to:

Step 6: Disconnect users from Canva

After a user authenticates with an app, they should be able to disconnect the app from Canva. Users can disconnect apps from Canva via the editor.

When a user disconnects an app, Canva sends a POST request to the following endpoint:

<authentication_base_url>/configuration/delete

The <authentication_base_url> placeholder refers to the app's Authentication base URL field, which you can set in the Developer Portal, via the app's Authentication page. Canva appends a value of /configuration/delete to this endpoint, so /configuration/delete must be omitted from the Authentication base URL field.

The body of this request includes a user property, which contains the ID of the user. The app can use this ID to remove the user's Canva ID in the platform's backend.

To learn more about the /configuration/delete endpoint, refer to the API reference.

Example

This example demonstrates a (very basic) implementation of authentication in a content extension. Use it to understand how authentication works, rather than direct inspiration for your own extensions.

const basicAuth = require('express-basic-auth');
const express = require('express');
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const querystring = require('querystring');
const app = express();
app.use(express.json());
app.use(express.static('public'));
// Set up the database
const adapter = new FileSync('db.json');
const db = low(adapter);
db.defaults({ users: [] }).write();
// Set up Redirect URL
app.get(
'/login',
basicAuth({
users: { admin: 'password123' },
challenge: true,
}),
async (request, response) => {
// Add the user to the database
db.get('users').push(request.query.user).write();
// Construct query parameters for redirect
const params = querystring.stringify({
success: true,
state: request.query.state,
});
// Redirect back to Canva
response.redirect(302, `https://canva.com/apps/configured?${params}`);
},
);
// Handle requests for content
app.post('/content/resources/find', async (request, response) => {
// Find the user in the database
const isLoggedIn = db.get('users').find(request.query.user).value();
// If the user isn't found, return an error
if (!isLoggedIn) {
response.send({
type: 'ERROR',
errorCode: 'CONFIGURATION_REQUIRED',
});
return;
}
// If the user is found, return some resources
response.send({
type: 'SUCCESS',
resources: [
{
type: 'IMAGE',
id: '123456',
name: 'Leaning Tower of Pisa',
thumbnail: {
url: 'https://picsum.photos/id/629/600',
},
url: 'https://picsum.photos/id/629/2000',
contentType: 'image/jpeg',
},
],
});
});
app.listen(process.env.PORT || 3000);