408 lines
15 KiB
Markdown
408 lines
15 KiB
Markdown
Skip navigation
|
||
|
||
Skip to main content
|
||
|
||
[](https://www.canva.com/developers/)
|
||
|
||
* [Home](/)
|
||
|
||
* Documentation
|
||
|
||
* Blogs
|
||
|
||
* [Your apps](https://www.canva.com/developers/apps)
|
||
|
||
* [Your integrations](https://www.canva.com/developers/integrations)
|
||
|
||
Getting started
|
||
|
||
[Overview](/docs/connect/)[Quickstart](/docs/connect/quickstart/)[Creating
|
||
integrations](/docs/connect/creating-integrations/)[Dev MCP
|
||
server](/docs/connect/mcp-server/)
|
||
|
||
Fundamentals
|
||
|
||
[API requests & responses](/docs/connect/api-requests-
|
||
responses/)[Authentication](/docs/connect/authentication/)[API
|
||
versions](/docs/connect/versions/)[Canva concepts](/docs/connect/canva-
|
||
concepts/)[Security](/docs/connect/guidelines/security/)[Shared responsibility
|
||
model](/docs/connect/guidelines/shared-responsibility/)
|
||
|
||
Examples
|
||
|
||
[Autofill guide](/docs/connect/autofill-guide/)[Return navigation
|
||
guide](/docs/connect/return-navigation-guide/)
|
||
|
||
Guidelines
|
||
|
||
[Brand](/docs/connect/guidelines/brand/)[Recommended
|
||
practices](/docs/connect/guidelines/recommended-practices/)[User
|
||
interface](/docs/connect/guidelines/user-interface/)
|
||
|
||
Distributing integrations
|
||
|
||
[Submission checklist](/docs/connect/submission-checklist/)[Submitting
|
||
integrations](/docs/connect/submitting-integrations/)
|
||
|
||
API reference
|
||
|
||
Authentication
|
||
|
||
Assets
|
||
|
||
Autofill
|
||
|
||
Brand templates
|
||
|
||
Comments
|
||
|
||
Designs
|
||
|
||
Design imports
|
||
|
||
Exports
|
||
|
||
Folders
|
||
|
||
Resizes
|
||
|
||
Users
|
||
|
||
[Keys](/docs/connect/api-reference/webhooks/keys/)
|
||
|
||
Webhooks
|
||
|
||
Webhook notifications
|
||
|
||
Appendix
|
||
|
||
[Scopes](/docs/connect/appendix/scopes/)[Capabilities](/docs/connect/capabilities/)[Error
|
||
responses](/docs/connect/error-
|
||
responses/)[Changelog](/docs/connect/changelog/)[Zapier Canva
|
||
MCP](/docs/connect/zapier-mcp/)
|
||
|
||
# Authentication
|
||
|
||
Copy page
|
||
|
||
To start using the Canva Connect APIs, you need to authorize your users using
|
||
[OAuth 2.0(opens in a new tab or
|
||
window)](https://datatracker.ietf.org/doc/html/rfc6749).
|
||
|
||
OAuth lets your integration authenticate the user, get their authorization to
|
||
access the Connect API endpoints, and then perform actions on their behalf.
|
||
Specifically, the Connect APIs use OAuth 2.0 with the [Authorization Code flow
|
||
with Proof Key for Code Exchange (PKCE)(opens in a new tab or
|
||
window)](https://datatracker.ietf.org/doc/html/rfc7636) using SHA-256.
|
||
|
||
The authorization and authentication process involves the following steps:
|
||
|
||
1. Obtain authorization from the Canva user for the scopes that your integration requires. After the user authorizes your integration, you'll receive an authorization code at your specified redirect URL.
|
||
2. Use the authorization code to generate access tokens, which lets your integration access Connect API resources. This lets your integration act on the user's behalf.
|
||
|
||
There are libraries in various languages that provide support for handling the
|
||
OAuth process. For more information, see the [OAuth Community Site(opens in a
|
||
new tab or window)](https://oauth.net/code/).
|
||
|
||
You can also use the [Canva Connect API Starter Kit(opens in a new tab or
|
||
window)](https://github.com/canva-sdks/canva-connect-api-starter-kit) as a
|
||
starting point for an authorization and authentication implementation.
|
||
|
||
## Prerequisites
|
||
|
||
Before authenticating to the Canva Connect APIs, you must first create and
|
||
configure your integration in the Developer Portal, including:
|
||
|
||
* Setting an integration name
|
||
* Generating and saving a client secret
|
||
* Selecting scopes
|
||
* Setting at least one authentication redirect URL
|
||
|
||
For more information, see [Creating integrations](/docs/connect/creating-
|
||
integrations/).
|
||
|
||
## Obtain user authorization
|
||
|
||
To obtain user authorization, you must direct your users to Canva's
|
||
authorization URL. This lets a user review and approve access for your
|
||
integration.
|
||
|
||
### Create the authorization URL
|
||
|
||
The authorization URL that you direct users to is in the following format:
|
||
|
||
|
||
|
||
https://www.canva.com/api/oauth/authorize?code_challenge=<code challenge string>&code_challenge_method=s256&scope=<list of scopes>&response_type=code&client_id=<client ID>&state=<optional state>&redirect_uri=<redirect uri for your integration>
|
||
|
||
Copy
|
||
|
||
In your integration's settings in the [Developer Portal(opens in a new tab or
|
||
window)](https://www.canva.com/developers/integrations/), there is an
|
||
**Authorization URL generator** tool on the **Authentication** page that pre-
|
||
fills most of the parameters for an authorization URL. If you use this tool,
|
||
you must still provide your own `code_challenge` and `state` values, as well
|
||
as verify the values for the other query parameters.
|
||
|
||
Create the URL, starting with `https://www.canva.com/api/oauth/authorize?` and
|
||
add the following query parameters:
|
||
|
||
1. **`code_challenge`**
|
||
|
||
The `code_challenge` string you provide is derived from another string, a
|
||
`code_verifier`. You must first create a `code_verifier` value, and then
|
||
transform the `code_verifier` into the `code_challenge` string. For more
|
||
information, see the [PKCE specification(opens in a new tab or
|
||
window)](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1).
|
||
|
||
1. Create the `code_verifier` string. It must be a high-entropy cryptographically random string that is between 43 and 128 characters long. Only ASCII letters, numbers, and `-`, `.`, `_`, or `~` characters are allowed.
|
||
|
||
You must securely store the `code_verifier` string in your client, because
|
||
you'll use it later to generate an access token.
|
||
|
||
The `code_verifier` value must not be accessible by the user or their browser.
|
||
|
||
2. Generate the `code_challenge` string by SHA-256 hashing the `code_verifier` value and then encoding that result into a URL-safe base64 string.
|
||
|
||
You can use the [sample code shown
|
||
below](/docs/connect/authentication/#example-code-for-codeverifier-and-
|
||
codechallenge-strings) to generate the `code_verifier` and `code_challenge`
|
||
strings.
|
||
|
||
The `code_verifier` and `code_challenge` values should be unique for each
|
||
request.
|
||
|
||
2. **`code_challenge_method`**
|
||
|
||
This must be set to `S256` (SHA-256).
|
||
|
||
3. **`scope`**
|
||
|
||
This is a space-separated list of [scopes](/docs/connect/appendix/scopes/)
|
||
requested by your integration.
|
||
|
||
The scopes you request must already be set in your integration settings in the
|
||
Developer Portal. You can't request any scopes you haven't set in your
|
||
integration's settings. For information on setting scopes, see [Creating
|
||
integrations](/docs/connect/creating-integrations/#step-3-set-scopes).
|
||
|
||
You must be explicit when listing scopes.
|
||
|
||
For example, specifying `asset:write` doesn't grant `asset:read` permissions.
|
||
You must specify _both_ in the scope string, for example: `asset:read
|
||
asset:write`.
|
||
|
||
4. **`response_type`**
|
||
|
||
This must be set to `code`.
|
||
|
||
5. **`client_id`**
|
||
|
||
This value is the unique ID that identifies your client. You can get this
|
||
value from your integration settings in the [Developer Portal(opens in a new
|
||
tab or window)](https://www.canva.com/developers/integrations/connect-api).
|
||
|
||
6. **`state`** (Optional)
|
||
|
||
The `state` parameter serves two primary purposes:
|
||
|
||
* It acts as a countermeasure against [Cross-Site Request Forgery (CSRF)(opens in a new tab or window)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks by maintaining a unique session state between your integration and the Canva API. For more information, see the [OWASP Cross-Site Request Forgery Prevention Cheat Sheet(opens in a new tab or window)](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
|
||
* It helps preserve the application state through the OAuth flow.
|
||
|
||
Although this parameter is optional to include in the authorization URL, it's
|
||
highly recommended. It makes sure that the response your integration receives
|
||
corresponds to the request initiated by the user, thereby preventing bad
|
||
actors from forging requests.
|
||
|
||
When creating the `state` value, it must be a high-entropy random string and
|
||
it should be unique for each request. You can use the [sample code shown
|
||
below](/docs/connect/authentication/#example-code-for-state-string) to
|
||
generate the `state` string.
|
||
|
||
You must securely store the `state` string in your client, so you can use it
|
||
later to verify the response.
|
||
|
||
The `state` parameter must not be used to store the `code_verifier` value.
|
||
|
||
7. **`redirect_uri`** (Optional)
|
||
|
||
This is the URL to redirect the user to after they authorize your integration.
|
||
|
||
Although this parameter is optional to include in the authorization URL, you
|
||
must have at least one redirect URL set in your integration settings in the
|
||
Developer Portal. The URL set in this query parameter must be one that you
|
||
have already set in your integration settings.
|
||
|
||
If you have _only one_ redirect URL set in your integration settings, you
|
||
don't need to provide this parameter.
|
||
|
||
If you have multiple redirect URLs set in your integration settings and this
|
||
query parameter isn't supplied in the authorization URL, then the first
|
||
redirect URL that's set in your integration's settings is used by default.
|
||
|
||
After adding the preceding query parameters, an example authorization URL
|
||
might look similar to the following:
|
||
|
||
`https://www.canva.com/api/oauth/authorize?code_challenge=eeeAbcdefgh123456789Vz96F9UIv8EHwnmibz3Djx3EE&code_challenge_method=s256&scope=asset:read%20asset:write%20design:meta:read%20folder:read%20comment:write&response_type=code&client_id=OCABC12-DeF`
|
||
|
||
#### Example code for `code_verifier` & `code_challenge` strings
|
||
|
||
You can use the following sample code to generate the `code_verifier` and
|
||
`code_challenge` strings.
|
||
|
||
|
||
|
||
import crypto from "crypto";
|
||
|
||
const codeVerifier = crypto.randomBytes(96).toString("base64url");
|
||
|
||
const codeChallenge = crypto
|
||
|
||
.createHash("sha256")
|
||
|
||
.update(codeVerifier)
|
||
|
||
.digest("base64url");
|
||
|
||
JS
|
||
|
||
Copy
|
||
|
||
#### Example code for `state` string
|
||
|
||
|
||
|
||
import crypto from "crypto";
|
||
|
||
const state = crypto.randomBytes(96).toString("base64url");
|
||
|
||
JS
|
||
|
||
Copy
|
||
|
||
### Send the user to the authorization URL
|
||
|
||
You must direct your users to the authorization URL that you created to get
|
||
their approval for your integration and the requested scopes.
|
||
|
||
They will see a prompt similar to the following:
|
||
|
||

|
||
|
||
After they authorize your integration, they are redirected to your redirect
|
||
URL with the following query parameters:
|
||
|
||
`code```
|
||
|
||
Required
|
||
|
||
The authorization code you can use to [generate an access
|
||
token](/docs/connect/authentication/#generate-access-tokens).
|
||
|
||
`state```
|
||
|
||
Optional
|
||
|
||
The value of the `state` parameter, if it was provided with the initial
|
||
request.
|
||
|
||
To prevent forgery of cross-site requests, you must verify that the received
|
||
`state` value matches the one in the authorization URL you sent to the user.
|
||
If they don't match, you must stop the authorization flow and return an error
|
||
to the user.
|
||
|
||
## Generate access tokens
|
||
|
||
After you've obtained user authorization and received an authorization code,
|
||
you can exchange the code for an access token (that lets you act on the user's
|
||
behalf) and a refresh token (that you can use to get new access tokens).
|
||
|
||
Because access tokens are only valid for a short period time, you can handle
|
||
requesting new access tokens using a refresh token instead of having to re-
|
||
authorize the user to get a new authorization code.
|
||
|
||
An overview of the token request process is shown in the diagram below:
|
||
|
||

|
||
|
||
Token request flow (Adapted from the OAuth 2.0 specification).
|
||
|
||
Requests that require authenticating with your client ID and client secret
|
||
can't be made from a web-browser client. They must come from your backend,
|
||
otherwise they'll be blocked by Canva's [Cross-Origin Resource Sharing
|
||
(CORS)(opens in a new tab or window)](https://developer.mozilla.org/en-
|
||
US/docs/Web/HTTP/CORS) policy.
|
||
|
||
### Use an authorization code
|
||
|
||
To exchange an authorization code for an access token, use the [Generate an
|
||
access token endpoint](/docs/connect/api-reference/authentication/generate-
|
||
access-token/).
|
||
|
||
Some points to note when using the endpoint with an authorization code:
|
||
|
||
* Requests to the endpoint must be authenticated, and we recommend using the [basic access authentication(opens in a new tab or window)](https://en.wikipedia.org/wiki/Basic_access_authentication) method. For basic access authentication, the `{credentials}` string must be a Base64 encoded value of `{client id}:{client secret}`.
|
||
* When exchanging an authorization code for an access token, you must set `grant_type` to `authorization_code` .
|
||
* You must provide the `code_verifier` value that you generated when [creating the user authorization URL](/docs/connect/authentication/#create-the-authorization-url).
|
||
* You must provide the authorization code you received after the [user authorized your integration](/docs/connect/authentication/#send-the-user-to-the-authorization-url).
|
||
|
||
The endpoint reference includes [example request code](/docs/connect/api-
|
||
reference/authentication/generate-access-token/#example-request) in various
|
||
languages.
|
||
|
||
A successful response from the endpoint includes the access token, the expiry
|
||
time for the token, and a refresh token.
|
||
|
||
### Use a refresh token
|
||
|
||
When an access token expires or becomes invalid, you can use a refresh token
|
||
from a previous access token request to get a new access token.
|
||
|
||
Refresh tokens can't be used to access resources on protected APIs. They are
|
||
only used for generating new access tokens.
|
||
|
||
To exchange a refresh token for an access token, you again use the [Generate
|
||
an access token endpoint](/docs/connect/api-reference/authentication/generate-
|
||
access-token/).
|
||
|
||
Some points to note when using the endpoint with a refresh token:
|
||
|
||
* Requests to the endpoint must be authenticated, and we recommend using the [basic access authentication(opens in a new tab or window)](https://en.wikipedia.org/wiki/Basic_access_authentication) method. For basic access authentication, the `{credentials}` string must be a Base64 encoded value of `{client id}:{client secret}`.
|
||
* When exchanging a refresh token for a new access token, you must set `grant_type` to `refresh_token`.
|
||
* You must provide a refresh token from a previous token request.
|
||
* Each refresh token can only be used once.
|
||
|
||
A successful response from the endpoint includes a new access token, the
|
||
expiry time for the new token, and another refresh token.
|
||
|
||
## Introspect an access token
|
||
|
||
You can use the [Introspect an access token](/docs/connect/api-
|
||
reference/authentication/introspect-access-token/) endpoint to see whether an
|
||
access token or refresh token is valid and active. You can also verify some
|
||
token properties, such as its claims, scopes, and validity times.
|
||
|
||
## Revoke a token
|
||
|
||
If necessary, you can use the [Revoke a token](/docs/connect/api-
|
||
reference/authentication/revoke-token/) endpoint to revoke an access token or
|
||
refresh token.
|
||
|
||
[Community](https://community.canva.dev/)[Get Help](https://canva-
|
||
external.atlassian.net/servicedesk/customer/portal/2/group/2)[GitHub](https://github.com/canva-
|
||
sdks/canva-connect-api-starter-kit)
|
||
|
||
Was this page useful?YesNo
|
||
|
||
* * *
|
||
|
||
© 2025 All Rights Reserved. Canva®
|
||
|
||
[Privacy policy](https://www.canva.com/policies/privacy-
|
||
policy/)[Terms](https://www.canva.com/policies/)
|
||
|
||
[](https://www.facebook.com/canva)[](https://x.com/canva)[](https://www.pinterest.com/canva)[](https://instagram.com/canva)
|
||
|