Appearance
Security Guidelines
Security Guidelines
How to keep your app (and its users) secure.
At Canva, the security of our platform is paramount, and we expect app developers to maintain similar standards. This page outlines some of the key recommendations to keep your app (and its users) secure.
<Note> Canva maintains some responsibility for security, but not all responsibilities. For a complete list of security responsibilities you'll need to consider for your app, see the Canva Apps SDK Shared responsibility model for Canva Apps </Note>
Use reasonable security measures
Security is a huge topic, and it's beyond the scope of this documentation to explain every measure you could take to keep an app secure, but a good starting point is to ensure your app is not vulnerable to the OWASP Top 10.
Respect Canva's Content Security Policy
Canva applies a Content Security Policy (CSP) to the app's iframe. This policy prevents apps from loading certain resources within the iframe, such as third-party scripts. Apps can't circumvent the policy, but the app may break in surprising ways if it violates the policy, so it's important to be mindful of the restrictions.
To learn more, see Content Security Policy.
Configure Cross-Origin Resource Sharing
Cross-Origin Resource Sharing (CORS) is a security feature of web browsers that blocks client-side HTTP requests between different origins. We recommend setting the most restrictive policy possible.
To learn more, see Cross-Origin Resource Sharing.
Verify HTTP requests
When an app sends an HTTP request to a backend, the backend should verify that the request is from a known, trusted source. This prevents bad actors from sending arbitrary (and potentially malicious) requests to the backend.
For Node.js backends, we recommend using the @canva/app-middleware package, which provides built-in JWT verification, JWKS caching, and error handling.
To learn more, see HTTP request verification.
Store secrets securely
Apps often need to store secrets and tokens, such as API keys or access tokens. There are inherent risks to this, so it's important to consider those risks and mitigate against them.
Here's what we recommend:
- When extracting information about the current user from a JSON Web Token (JWT), always verify the token. This ensures the token has not been tampered with. For Node.js backends, use the
@canva/app-middlewarepackage for secure JWT verification. To learn more, see JSON Web Tokens. - When integrating with third-party services, use tokens that have the least amount of access to that service as possible. This reduces the potential impact of a breach.
- Use storage mechanisms, such as JavaScript closures instead of WebStorage APIs, to store sensitive values such as API keys. WebStorage APIs can be accessed by anyone with access to the machine, simply by opening the browser's developer tools.
- Keep secrets and tokens masked from users after they are stored in a database; avoid logging them to the console or displaying them after creation.
- Use rate-limiting to prevent the misuse of tokens.
- Transmit tokens securely using
POSTrequests rather than including them in the URL query string, to avoid exposure through third-party logging. - Always associate access tokens with the combination of the ID of the user and the ID of their team. This ensures that, if a user is removed from the team, their access through the app is also revoked.
- If an access token is no longer needed, delete the token immediately. For example, delete access tokens as soon as a user deletes their account, data, or connection between Canva and a third-party platform.
- Maintain strict token and capability isolation, ensuring that all token-bound functionality is available only to the user it was issued to.
- Use Transport Layer Security (TLS) protocols and ciphers to encrypt traffic between your app, its backend, and other services. This ensures any access tokens or secrets are never transmitted unencrypted.
Maintain ownership of subdomains
Many apps rely on dedicated subdomains to host backend services, identity endpoints, or other functional components. Because these subdomains often represent trusted surfaces to both users and relying parties, it's essential to ensure they remain properly configured and under your control at all times.
A subdomain may become vulnerable if its DNS records point to a resource that's unclaimed, de-provisioned, or misconfigured. This can enable a subdomain takeover, where an attacker gains control of the subdomain and can serve malicious content or impersonate your service.
For example, if an attacker controls any of these subdomains, they may be able to:
- Issue fraudulent tokens or present malicious signing keys
- Steal authorization or refresh tokens
- Spoof authentication or authorization flows
- Intercept or manipulate redirect flows
- Masquerade as your IdP or authorization server
Because modern authentication protocols rely heavily on domain trust, you must monitor and secure these subdomains.
To reduce the risk of subdomain takeover, we recommend you do the following:
- Regularly verify that any referenced service is actually running and under your control.
- If a backend or identity service is decommissioned or migrated, update your DNS configuration immediately.
- Make sure you have strict lifecycle oversight of these subdomains because of the severe impact of compromise.
- Check DNS configurations, hosting status, and any service-specific ownership checks.
- Avoid pointing subdomains to temporary, unmanaged, or short-lived resources unless you have processes ensuring they can't become orphaned.
- Monitor for misconfigurations or unintended DNS targets. Even short periods of misalignment can be enough for an attacker to claim a subdomain.
- Document subdomain lifecycle events, including provisioning, migration, and decommissioning, as part of your operational security practices.
Don't require users to download files
Your app should never ask or require users to download external files — especially executable ones. External files are a significant security risk and, at the very least, requiring users to download them erodes trust.
Shared Responsibility
Shared security responsibilities for developing Canva Apps.
Background
Shared responsibility models clarify security responsibility between a platform provider and developers building apps that connect to that platform.
Building apps that connect to Canva means that developers share the same users as Canva. As a result, developers must take some responsibility to protect user data and privacy, which can differ from other Software as a Service (SaaS) product expectations. Canva, as a provider, takes some responsibility, but not all of the security responsibility.
Read through the following sections to understand your security responsibilities, as well as Canva's responsibilities.
<Note> Make sure that you read, and are complying with, the Canva API and App Developer Terms.
Noncompliance may result in Canva:
- Suspending your app
- Disabling access to it from the Canva App Marketplace </Note>
We reserve the right to amend this page from time to time at our sole discretion.
<Note> For specific recommendations on how to security harden your app, see the Security guidelines. For more information on authorization security, see the Content Security Policy and the guide on Verifying JWTs. For authentication steps, see the guide on Authenticating users. </Note>
App concepts
Canva apps
Apps are plugins that add features to Canva. They run in the browser and are built with standard web technologies, such as JavaScript. Apps are built using the Canva Apps SDK, which is made up of libraries and capabilities that combine to build feature-rich apps. The Canva Apps SDK enables your app to:
- Use standard web technologies to render a user interface.
- Use the Fetch API to integrate with the app's backend.
- Use the Apps SDK to integrate with the core Canva experience.
App architecture
The App architecture is comprised of the following components:
- App SDK Libraries - methods that let you invoke App SDK functionality.
- UI Components (optional) - a component suite that lets you define app user interfaces using a React-based component library.
- App backend (optional) - an application server that allows you to complete complex computations, expose additional resources, or store additional information your users require.
App changes
Security responsibilities can change as you build your app. For example, if you're providing complex computations through an app backend, and storing additional information for users, you'll have additional responsibilities to maintain the security of the app backend. It's important to be aware of how your responsibilities could change if your app changes scope.
Security operations
Vulnerability management and disclosure
Minimize security incidents through early identification of vulnerabilities and timely remediation. Provide a framework to manage the constantly changing vulnerability landscape.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Conduct regular security reviews of infrastructure and source code using vulnerability scanning tools, vulnerability disclosure programs, or penetration testing by external parties. | Suspend apps that haven't mitigated security vulnerabilities, as explained in the Canva API and App Developer Terms. |
| Mitigate or remediate app security vulnerabilities, in accordance with the Canva API and App Developer Terms. | Communicate with developers about vulnerabilities, in apps or the platform, that may affect their apps. |
| Notify Canva of critical or high security vulnerabilities discovered in your app, in accordance with the Canva API and App Developer Terms.. |
Monitoring and alerting
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure adequate monitoring and alerting is implemented for backend functionality to ensure the timely identification and containment of security events or incidents. | Ongoing monitoring of App SDK platform health, raising alerts in response to degraded performance, security, or abuse events. |
Logging
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure your app doesn't log sensitive security data, personally identifiable information, authentication tokens, and user-generated content, or any other data that might be deemed sensitive by your data classification policy. | Maintain robust logging that includes an audit trail of actions performed within Canva. |
| Ensure you implement adequate logging for backend functionality to ensure the timely identification and containment of security events or incidents. | Restrict access to logs based on organization permissions. |
Incident response
As the frequency of security vulnerabilities increases, your incident response plan becomes crucial. It's essential to have effective measures in place to detect and respond to unauthorized access to your systems and data.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Promptly notify Canva of any incidents involving Canva SDK app data in accordance with the Canva API and App Developer Terms. | Maintain a detailed action plan for responding to security incidents, including steps to contain and remediate the attack, and communicate with stakeholders. |
| Develop a detailed action plan for responding to security incidents, including steps to contain and remediate the attack, and communicate with users. | Regularly test the incident response plan to ensure its effectiveness. |
| Regularly test your incident response plan to ensure its effectiveness. |
Network security
Ensure appropriate network security controls are implemented preventing threat actors from accessing sensitive information while requests are in transit between services.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Use secure protocols and configurations to encrypt traffic between your integration and backend, and between internal services. | Ensure that modern, secure protocols are supported by the platform. |
| Handle data collected and stored in your backend according to your data classification policy, or with current best practice. |
Infrastructure security
Maintain the integrity, confidentiality, and availability of underlying infrastructure, and provide a safe computing environment.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure that you have hardened the app backend, and any associated services. For more information see OWASP Web Service Security Cheat Sheet and the OWASP Database Security Cheat Sheet. | Ensure the platform infrastructure is hardened. |
| Scan regularly for security misconfigurations and vulnerabilities. | Scan regularly for security misconfigurations and vulnerabilities. |
| Use the provided runtime in a way that doesn't purposely try to bypass security controls. | Provide a secure runtime for apps that prevents bypassing security controls. |
Disaster recovery
Data, source code, and other business assets underpin your apps and related system functionality. It's important to minimize the impact of accidental or malicious disasters with an action plan or other recovery mechanism.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Establish a business continuity and disaster recovery plan to minimize the impact of outages to the functionality of your app during incidents, or after an accidental or malicious disaster. | Ensure that data stored by Canva on behalf of your app is backed up, and can be reasonably restored in an incident. |
| Maintain business continuity and disaster recovery plans. |
Subdomain ownership and lifecycle management
Subdomains used by apps, especially those hosting authentication, authorization, or identity-related services, must be actively maintained to prevent unauthorized control. Subdomain takeover occurs when a DNS record points to an unclaimed, de-provisioned, or misconfigured resource. If an attacker gains control of such a subdomain, they can impersonate legitimate services, intercept requests, or distribute malicious content under a trusted domain.
This risk is particularly significant when subdomains are used for OAuth/OIDC authorization servers, identity providers (IdPs), or other security-critical surfaces.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Maintain ownership and active configuration of any service referenced by DNS records (for example, A, CNAME, or ALIAS records). | Monitor Canva-owned subdomains for takeover indicators or misconfigurations. |
| Remove or update DNS entries that point to resources that have been deleted, renamed, expired, or migrated. | Suspend or restrict apps that introduce critical subdomain risks, in line with the Canva API and App Developer Terms. |
| Validate ownership and claim status regularly, ensuring referenced infrastructure is actively provisioned. | |
Monitor for dangling DNS records, particularly for subdomains associated with OAuth/OIDC authorization servers, identity providers (IdPs), token and introspection endpoints, /.well-known/openid-configuration metadata, JWKS endpoints, and redirect URIs or callback handlers. | |
| Ensure that security-critical subdomains are never delegated to unmanaged or temporary resources without proper lifecycle controls. | |
| Respond promptly to notices about misconfigurations or potential takeover conditions. | |
| Document subdomain lifecycle events, including provisioning, migration, and decommissioning, as part of your operational security practices. |
Trust and safety
User identity and access management
| Your responsibilities | Canva's responsibilities |
|---|---|
| Verify user and team access to content before serving that content to a user using available mechanisms. | Authenticate user and team membership. |
| Use authentication APIs for third-party platform access. | Provide authentication APIs for third-party platform access. |
| Provide a mechanism for apps to verify user and team access to Canva content. |
Denial-of-service prevention
Denial-of-Service (DoS) attacks deliberately and maliciously disrupt API, system, and site operations. DoS attacks degrade user experience. Protect your app with detection and mitigation mechanisms.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Detect DoS attacks against app backends. | Detect DoS attacks executed through app frontends, or caused by apps. |
| Mitigate DoS attacks against app backends. | Mitigate DoS attacks executed through app frontends, or caused by apps. |
| Suspend apps that might be misbehaving or insufficiently managing high volumes of requests. |
Abuse prevention
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure your app works in accordance with the restrictions outlined in Section 5 of the Canva API and App Developer Terms. | Detect and mitigate apps that disrupt the normal operations of Canva or other Canva apps. |
| Ensure your app does not exceed the Canva API and App SDK platform quotas and limits. | Enforce platform limits, such as for storage and request throughput. |
App
Authenticating requests to the app
Ensure that all requests made to apps are sufficiently authenticated.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Authenticate users to your app, or the third-party platform, before serving additional content. | Provide a secure mechanism to authenticate with apps, or other third-party platforms. |
| Adhere to current best security practices when authenticating to your platform, or to third-party platforms. | Ensure state token authenticity is verified before proceeding to the next step in the authentication workflow. |
| Ensure you have verified nonce token authenticity before proceeding to the next step in the authentication flow. | Authenticate the user to Canva before launching your Canva app. |
Authorizing requests from the app
Ensure that every request made from apps to your backend is sufficiently authorized.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Verify the authenticity of incoming requests to your app backend. | Obtain user consent before launching your Canva app. |
| Verify that the user and team are authorized to access content before serving it. | Ensure that only users with access to Canva can interact with apps. |
| Verify the user and team are authorized to access additional content being served through a third-party platform before providing access. | For private apps, ensure that only users with access to the team can interact with the app. |
| Ensure that adequate controls are in place to prevent cross-site request forgery. |
Authorizing requests to the app
Ensure that every request made from your backend to your app is sufficiently authorized.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Verify the authenticity of incoming requests to your app from your app backend. |
App framework
Ensure frameworks and third-party libraries used to build apps are free of security bugs, and you’re applying fixes in line with the Canva API and App Developer Terms.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure the frameworks and third-party libraries used in your app are up-to-date with the latest security patches. | Apply secure development culture and practices when building the app framework. |
| Remediate defects and vulnerabilities within the App SDK framework. |
Input validation and output encoding
Ensure sufficient input validation and output encoding within apps. For example, when returning HTML to render in the app's UI, ensure that you use HTML entity encoding for variables added to the web template. This helps protect users from attacks like cross-site scripting.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Treat all user input as unsafe and untrusted, regardless of the input source. | Appropriately encode all HTML output for UI Components. |
| Adhere to current best security practices when providing or consuming data from third-party platforms. | |
| Validate data sent to your app, and ensure you encode data appropriately. |
Business logic
Protect the legitimate process flow of an app, and don't expose the process flow in ways that results in negative consequences.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Identify and remediate business logic flaws through regular testing. | |
| Apply security controls in layers to mitigate business logic flaws. |
Tenant security
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure isolation between apps. An app, 'App A', cannot communicate with 'App B'. | |
| Ensure isolation between users and teams. For example, 'Team A' can access 'App A'. Even if 'App A' is made available for 'Team B', a user in 'Team A', cannot use 'App A' to access the data of 'Team B'. |
Data storage
Appropriately manage data throughout its lifecycle, from data entry to data destruction.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Ensure that data collected and processed is minimized to only collect what's required for the app to function as intended. | Maintain web storage separation and cleanup between user sessions. |
| Ensure that sensitive security data, such as API keys, pre-shared keys, or encryption keys, aren't hard-coded in source code. For more information see the OWASP Secrets Management Cheat Sheet and the OWASP Password Storage Cheat Sheet. | |
| Ensure that sensitive security data, such as API keys, pre-shared keys, and encryption keys, aren't persisted. | |
| Ensure that appropriate processes are in place to handle the revocation and rotation of sensitive security data. | |
| Ensure that any personal information collected by your app is handled in accordance with your data classification policy, applicable data protection, and privacy legislation. | |
| Limit disclosure of confidential information shared with employees, contractors, legal, or financial and accounting advisors to a need to know basis, as outlined in the Canva API and App Developer Terms. |
Secure development activities
A secure software development framework is a set of functional practices that, when applied appropriately, can achieve the following:
- Reduce the number of vulnerabilities in released software.
- Reduce the potential impact of the exploitation of undetected or unaddressed vulnerabilities.
- Address the root causes of vulnerabilities to prevent reoccurrences.
| Your responsibilities | Canva's responsibilities |
|---|---|
| Adopt secure software development frameworks or practices that aid in the identification, prioritization, and remediation of security vulnerabilities. For more information see the OWASP Secure Product Design Cheat Sheet. | |
| Perform regular threat modelling on apps and their critical paths to identify, prioritize, and remediate threats that might impact the security of your app. |
Verifying HTTP Requests
How to verify the authenticity of HTTP requests.
At their most basic, apps are web pages embedded in an iframe. As a result, they have access to many standard web APIs, including the Fetch API.
Using the Fetch API in an app is the same as using it anywhere else, but before you can release your app publicly, we require that your app's backend verifies the authenticity of incoming requests. This ensures that requests are arriving from the app and not from some other, potentially malicious source.
For Node.js backends, the @canva/app-middleware package simplifies the verification process by automatically handling token extraction, JWKS fetching, and JWT validation.
Warning: Some standard web APIs aren't available. To learn more, see Content Security Policy.
Step 1: Get a JWT from Canva
Before an app sends an HTTP request to its backend, it must request a JSON Web Token (JWT) from Canva. The app's backend can use this JWT to verify that the request is legitimate.
To get a JWT:
Import the
authnamespace from the@canva/userpackage:tsimport { auth } from "@canva/user";Call the
getCanvaUserTokenmethod:tsconst token = await auth.getCanvaUserToken();This method returns a JWT as a string.
Step 2: Send a request
Use the Fetch API, or a library such as axios, to send an HTTP request:
tsconst response = await fetch("http://localhost:3001/my/api/endpoint");In the headers of the request, include an
Authorizationheader:tsconst response = await fetch("http://localhost:3001/my/api/endpoint", { headers: { Authorization: `Bearer ${token}`, }, });The header should contain the word
Bearerand the JWT, separated by a space.
Step 3: Verify the request
To verify the request, you can either use the @canva/app-middleware package (recommended), or manually implement your own verification.
Recommended: Using @canva/app-middleware
For Node.js backends, use the @canva/app-middleware package to automatically verify requests:
Express.js middleware
typescript
import express from "express";
import { user } from "@canva/app-middleware/express";
const app = express();
// Apply middleware to verify all requests
app.use("/my/api", user.verifyToken({ appId: process.env.CANVA_APP_ID }));
app.post("/my/api/endpoint", (req, res) => {
// Access verified user information
const { userId, brandId } = req.canva.user;
// Your application logic here
res.sendStatus(200);
});
app.listen(process.env.PORT || 3000);For more information, see user.verifyToken.
Framework-agnostic approach
For other Node.js environments:
Alternative: Manual verification
If you're using a non-Node.js backend, you can manually extract and verify JWTs. Here's an example using Python with Flask:
Step 3a: Extract the JWT
When the backend receives a request, extract the JWT from the Authorization header:
python
from flask import Flask, request, jsonify
from functools import wraps
app = Flask(__name__)
def extract_token(auth_header):
"""Extract JWT from Authorization header"""
if not auth_header:
return None
parts = auth_header.split()
if len(parts) != 2 or parts[0].lower() != 'bearer':
return None
return parts[1]
@app.route('/my/api/endpoint', methods=['POST'])
def api_endpoint():
auth_header = request.headers.get('Authorization')
token = extract_token(auth_header)
if not token:
return jsonify({'error': 'Unauthorized'}), 401
# Verify token (see next step)
# ...
return jsonify({'message': 'Success'}), 200If the Authorization header doesn't contain a token, reject the request with a 401 status code.
Step 3b: Verify the JWT
By itself, the JWT is an indecipherable string. To get useful information out of the JWT, it needs to be decoded and verified. To learn how to do this, see JSON Web Tokens.
Step 3c: Reject invalid requests
The verified JWT is an object that should contain the following properties:
aud- The ID of the app.brandId- The ID of the user's team.userId- The ID of the user.
If any of these properties aren't available, reject the request with a 401 status code:
python
if not verified.aud or not verified.brandId or not verified.userId:
return jsonify({'error': 'Unauthorized'}), 401API reference
auth.getCanvaUserToken
Verifying JWTs
How to verify a JSON Web Token (JWT).
For security reasons, Canva uses JSON Web Tokens (JWTs) to encode certain information, such as the ID of the user or the ID of a user's design. To access this information, apps must decode and verify the JWTs.
Danger: Apps must only verify JWTs through the app's backend — never through the frontend.
<Note> For Node.js backends: We recommend using the @canva/app-middleware package, which provides built-in verification for both user tokens and design tokens, along with JWKS caching and error handling. This package simplifies the verification process and follows security best practices. </Note>
Types of tokens
In the Apps SDK, there are two types of tokens:
- Design tokens - Encode information about the current design, such as the ID of the design
- User tokens - Encode information about the current user, such as the ID of the user and their team
The steps for verifying each type of token are the same, but the tokens encode different information, and apps access them in different ways:
- An app can call the
getDesignTokenmethod. This method returns a design token, which the app can use to get the ID of a design and associate data with that design. To learn more, see Using design IDs. - An app can start an authentication flow. This redirects the user to the app's Redirect URL. Canva appends a user token to the URL. The app's backend can use this token to authenticate the user using a third-party platform.
- An app can call the
auth.getCanvaUserTokenmethod. This method returns a user token, which the app can use to verify HTTP requests or identify users (for example, to check if they're authenticated).
Verifying JWTs with @canva/app-middleware
For Node.js backends, the @canva/app-middleware package provides a simple and secure way to verify JWT tokens.
Installation
shell
npm install @canva/app-middlewareExpress.js middleware
For Express.js applications, use the built-in middleware:
<Tabs> <Tab name="User tokens" />
<Tab name="Design tokens" /> </Tabs>
Framework-agnostic function
For other Node.js environments (Next.js, AWS Lambda, Cloudflare Workers, and so on):
<Tabs> <Tab name="User tokens" />
<Tab name="Design tokens" /> </Tabs>
Manually verifying JWTs
If you're using a non-Node.js backend, you can manually verify JWTs. The following steps show how to implement JWT verification from scratch in TypeScript, which you can then adapt to your preferred language or framework.
Step 4: Verify the token
Use the public key to verify the JWT:
ts
const verified = jwt.verify("JWT_GOES_HERE", publicKey, {
audience: "YOUR_APP_ID",
});The exact syntax will depend on the library you're using.
If the token is valid, the verified token will be a dictionary. The properties in this dictionary will depend on whether the token is a design token or a user token.
Design tokens
If the token is a valid design token, the object will contain the following properties:
aud- The ID of the app.designId- The ID of the current design.
If these properties aren't available, it means the token or public key are invalid:
tsx
if (!verified.aud || !verified.designId) {
throw new Error("The design token is not valid");
}User tokens
If the token is a valid user token, the object will contain the following properties:
aud- The ID of the app.brandId- The ID of the user's team.userId- The ID of the user.
If these properties aren't available, it means the token or public key are invalid:
tsx
if (!verified.aud || !verified.brandId || !verified.userId) {
throw new Error("The user token is not valid");
}