Authenticating users

How to authenticate users via third-party platforms.

Authentication in Canva is about creating a seamless experience by ensuring that your app remembers your users. How you create this experience in your app can depend on the type of app and how you want to store your user data.

Check out the Authentication design guidelines

Our design guidelines help you create a high-quality app that easily passes app review.

Apps can handle users with two forms of authentication:

  • Frictionless authentication (preferred): This is an way to ensure that user data or credentials are automatically remembered to help users retain data, even without them passing through a login screen.
  • Manual authentication: Apps can require users to authenticate with third-party platforms to access certain content or features within an app.

Users confronted with a log-in prompt could consider it a hurdle. Any hurdles in the onboarding process come with a chance for them to drop out of your funnel, maybe to never return again. To help change the way authentication is viewed in the community, we want app developers to consider frictionless authentication.

Frictionless authentication is when you use the Canva user tokens API to:

  • Find out information about your users
  • Track your users and what they're doing with your app.

With this, you can do away with authentication entirely or delay traditional, manual authentication until a user tests your app to see the value it provides.

Using the auth.getCanvaUserToken method you can:

  • Retrieve a token that uniquely identifies the Canva user and their associated brand
  • Store the user ID on your end
  • Identify usage with the user or identify.

We've seen that if a user experiences most of an app's features, they're less likely to abandon the flow than if they're required to authenticate up front.

  • Track usage: You can monitor how much a user has used your services in Canva, regardless of whether they have interacted with the design. This is especially useful for AI apps where there's a real cost to serve for running the model. Here, you do all the tracking using the data in your app's backend.
  • Track time in app: You can save the date the user initially created their account (When the user token was created), then compare that date to today's date to see how long they've been using your app.

The workflow looks like the following:

  1. The user interacts with your app. Canva assigns a unique user ID to the user.
  2. Canva tracks the usage using the Fetch API. This interaction, as well as the associated user and app ID, is stored in the app backend.
  3. Your app backend stores the user ID in a database.
  4. You, as the app developer exploring metrics, use the stored data to know more about your users.

Manual authentication is the more traditional approach when a user logs in via a third-party so they can access certain content or features within the app.

By doing this, you can:

  • Give users access to their personal content, such as photos or videos
  • Give users access to certain features based on their specific privileges
  • Monetize apps by offering features or content to paying customers.

These are some examples of apps that support authentication:

For more examples, see the Apps Marketplace.

By default, authentication is disabled.

To enable authentication:

  1. Log in to the Developer Portal.
  2. Navigate to an app via the Your apps page.
  3. Click Add authentication.
  4. Enable This app requires authentication.

When authentication is enabled, the following fields become active:

  • Redirect URL
  • Authentication base URL

In the following steps, we'll explore the expected values for these fields.

To authenticate users, apps need a Redirect URL — a page, hosted on the app's infrastructure, that allows a user to authenticate with the app's platform.

How a user authenticates isn't important. The Redirect URL could point to a login form with a username and password, an OAuth 2.0 authorization flow, or something else altogether. Canva's approach to authentication is inherently flexible.

At the start of an authentication flow, Canva appends the following parameters to the Redirect URL:

  • canva_user_token
  • state

These parameters make it possible to securely authenticate a user.

The canva_user_token parameter contains a JSON Web Token (JWT) that is unique to the user.

Your app's backend needs to:

  1. Get the ID of the user and their team by verifying the JWT.
  2. Use the IDs to create a mapping between the user in Canva and the user in the app's backend.

There are many ways to create a mapping, so it's not practical to document all of the possible options, but we can provide an example:

If your app's backend has a users table in its database, you could add an canvaId column to the table. This column could contain a composite key made up of the IDs. For example, if the user's ID is 123 and the ID of their team is 456, the composite key would be something like 123:456.

When a user authenticates via the Redirect URL, the app could save the composite key to the database. The app could then check for the existence of this key to determine if the user is authenticated.

The state parameter contains a token that's unique to each authentication flow. For security reasons, apps must temporarily store this token and return it to Canva at the end of the authentication flow. This protects the app against Cross-Site Request Forgery (CSRF) attacks.

You can choose how to store the token, but we recommend using a cookie.

  1. Import the auth namespace from the @canva/user package:

    import { auth } from "@canva/user";
  2. Call the requestAuthentication method:

    const result = await auth.requestAuthentication();

    This method opens a popup window and takes the user to the app's Redirect URL. The user then completes the authentication process within the popup window.

You can pass a context property into the requestAuthentication method:

const result = await auth.requestAuthentication({
context: "Hello world",
});

This property appends the given string to the Redirect URL. You can use this property to pass data to an app's backend at the start of an authentication flow.

These are some potential use-cases for the context property:

  • The app authenticates with a third-party service that supports custom domains and the user needs to provide a custom domain at the start of the authentication flow — for example, a self-hosted app like GitLab. The custom domain could be provided via the context property.
  • The app sets permissions based on the user's actions. For example, the app may requests minimal permissions by default but lets the user re-authenticate to access additional permissions later on. The requested permissions could be provided via the context property.

At the end of an authentication flow, the app needs to:

  • Know that the authentication flow has ended.
  • Know the outcome of the authentication flow.
  • Close the popup window.

If the user is able to successfully authenticate with the third-party platform, redirect them to the following URL from within the popup window:

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

Replace <STATE> with the value of the state token from the start of the authentication flow.

If the user is not able to authenticate — for example, they have too many failed login attempts — redirect them to the following URL:

https://www.canva.com/apps/configured?success=false&state=<STATE>&errors=<ERRORS>

Be sure to:

  • Replace <STATE> with the value of the state token from the start of the authentication flow.
  • Replace <ERRORS> with an array of one or more error codes. (You can use your own error codes.)

If you're performing the redirect via the app's backend, use a 302 redirect:

const params = new URLSearchParams({
success: "true",
state: "STATE_GOES_HERE",
});
const url = `https://www.canva.com/apps/configured?${params}`;
response.redirect(302, url);

If you're performing the redirect via the app's frontend, use the window.location.replace method:

const params = new URLSearchParams({
success: "true",
state: "STATE_GOES_HERE",
});
const url = `https://www.canva.com/apps/configured?${params}`;
window.location.replace(url);

When the popup window is closed, the requestAuthentication method returns an object with a status property that describes the result of the authentication flow:

const result = await auth.requestAuthentication();
console.log(result.status);

You can use the status property to render an appropriate user interface based on the result of the authentication flow — for example, rendering an error when the authentication fails.

The possible values of the status property are:

  • "COMPLETED" - The user was able to authenticate.
  • "DENIED" - The user was not able to authenticate.
  • "ABORTED" - The user closed the popup window.

When the status property is "DENIED", the object has a details property that contains an array of error codes. These are the error codes provided by the app when it redirected back to Canva (if any).

In the app's frontend, generate a JWT for the current user:

const token = await auth.getCanvaUserToken();

Then send an HTTP request to the app's backend with the JWT in the Authorization header:

const response = await fetch("https://localhost:3001/authenticated-endpoint", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});

When the backend receives the request:

  1. Get the ID of the user and their team by verifying the JWT.
  2. Use the IDs to check if the user is authenticated. How the app does this depends on how the app created a mapping between the user in their backend and the user on Canva.

If the user is authenticated, respond with whatever the frontend needs to render the authenticated content or features — for example, the user's photos or specific privileges.

If the user is not authenticated, respond to the request with an error. The frontend can use this error to restrict what the user has access to and to prompt them to authenticate.

After a user connects (installs) an app, they have the option of disconnecting (uninstalling) it.

If a user has authenticated with a third-party platform, disconnecting an app in Canva won't automatically remove the connection between Canva and the platform — as far as the platform is concerned, the user will still be authenticated.

This is a sub-par user experience for a couple of reasons:

  • Disconnecting an app signals the user's intent to no longer be associated with the app and the app should respect that intent.
  • If the user reconnects the app at a later time, they'll already be authenticated. This is confusing and inconsistent with how the rest of Canva works.

To solve this problem, Canva sends a POST request to the following endpoint:

<AUTHENTICATION_BASE_URL>/configuration/delete

<AUTHENTICATION_BASE_URL> is a placeholder for the app's Authentication base URL. This must be set to the URL of a server that hosts the /configuration/delete endpoint.

In the headers of the request, Canva includes an Authorization header that contains a JWT for the current user. Upon receiving the request, the app should:

  1. Get the ID of the user and their team by verifying the JWT.
  2. Use the IDs to find the user in the app's backend.
  3. Remove any connection between the user and Canva.

When the disconnection is complete, respond with a 200 status code and the following object:

{
"type": "SUCCESS"
}

To confirm that the disconnection flow is working, authenticate with the app, then disconnect and reconnect. You should have to re-authenticate to access any privileged content or features. You can use the two methods to create a seamless user experience and still help you as a developer.

How you create an app and create ways for users to authenticate can shape the user experience. The following are workflows you can consider to create a delightful authentication flow.

If a Canva user has an account with your app (for example, if they have previously accessed your app with Canva) fetching the user token should be enough for you to identify if they do. Then you can either:

  • Continue allowing them access to the content associated with that user token.
  • Prompt them to log in to their account using manual authentication.

A user might have an account with your app, but have never accessed your app through Canva, so you don't have a user token associated to them.

In this case we recommend adding non-blocking text such as 'Already have an account? Click here to sign in.' at the bottom of your app to provide them the opportunity to initiate the authentication process.

If the trial is time-based, you can save the date of initial account creation and then check if that date + [trial time period] is before today's date. If it is, then allow the user to continue accessing the app. If it is not, you can restrict the UI in the app until the user authenticates and subscribes to an appropriate plan.

If the trial is usage-based, track usage as above and then restrict usage of the app when the tracked usage is the same as your defined usage limit.

If your app is free, you can use tracking usage for your analytics to understand how users are using your app. Free apps typically see higher usage, which count towards your app usage award tier - so you can make money without ever needing to set up subscriptions or authenticating users!

If you implement a freemium model for your app, which allows a certain amount of free usage per month (same as free trial), get them to upgrade, but reset at the end of the month.

If they can only use certain features, consider:

  • Allowing access to those features within the free tier
  • When they want to try a paid feature, give them some access to trial it (and track as you would any other usage and then require users authenticate and then subscribe to continue using that feature).