Before prompting a user to authenticate, an app must check if the user is already authenticated. This ensures that users don't have to re-authenticate every time they open the app.
The Authentication capability itself doesn't support this feature, but you can implement it by sending an HTTP request to the app's backend.
Step 1: Set up an endpoint
In the app's backend, set up an endpoint for checking if the user is authenticated:
app.post("/authentication/check", async (request, response) => {// code goes here});
The name of the endpoint is not important.
Step 2: Generate a JSON Web Token
In the app's frontend, use the getCanvaUserToken
method to generate a JSON Web Token (JWT):
import { getAuthentication } from "@canva/authentication";const auth = getAuthentication();const token = await auth.getCanvaUserToken();
When an app calls the getCanvaUserToken
method, the planned behavior is for Canva to generate a JWT via its backend. At this stage though, the backend for Canva has not been implemented.
As a stop-gap, we've provided a mock server in the starter kit that mimics the planned behavior.
To run the mock server:
-
Copy the ID of an app from the Your apps page.
-
In the starter kit's
.env
file, setCANVA_APP_ID
to the ID of the app. -
Run the following command:
npm run start:mock-canva-backend
The mock server must run concurrently with the app's frontend and backend servers.
When Canva's actual backend is released, the app can be updated to point to Canva's server, rather than the local server. No additional changes will be required.
Step 3: Send a request
Use the fetfch
method to send request to the app's backend:
const response = await fetch("https://localhost:3001/authentication/check", {method: "POST",headers: {Authorization: `Bearer ${token}`,},});
You must include the token in the Authorization
header.
This is the standard way to send any type of HTTP request from an app — not just authentication-related requests. To learn more, see Sending requests.
Step 4: Extract the ID of the user and team from the JWT
Upon receiving a request, the app's backend must decode and verify the JWT. The decoded JWT contains the ID of the user and their team:
import jwt from "jsonwebtoken";const verifiedToken = jwt.verify("TOKEN GOES HERE", "PUBLIC KEY GOES HERE");console.log(verifiedToken.userId); // The ID of the userconsole.log(verifiedToken.brandId); // The ID of the user's team
In the starter kit example backend, these values are available via a response.locals
object:
app.post("/authentication/check", (request, response) => {console.log(response.locals.userId);console.log(response.locals.brandId);});
If you have a custom backend, some manual work is required. To learn more, see Verifying requests.
You can use the ID of the user and their team to check if the user is authenticated. (The exact steps for determining their authentication status depends on how the app has implemented authentication.)
Step 5: Return a response
Respond to the request with the user's authentication status. You might also want to include additional details about the user, such as their username and avatar.
The following snippet is a minimal example of what the logic could look like:
app.post("/authentication/check", async (request, response) => {// Get the ID of the userconst userId = response.locals.userId;// Load the databaseconst data = await db.read();// Check if the user is authenticatedconst isAuthenticated = data.users.includes(userId);// Return the authentication statusresponse.send({isAuthenticated,});});
Step 6: Handle the response
When the frontend receives a response, either:
- Prompt the user to start an authentication flow, if they're not authenticated,
- Show the user restricted content or features, if they are authenticated
The following snippet demonstrates how this logic could be implemented in a React component:
import React from "react";import { getAuthentication } from "@canva/authentication";type State = "authenticated" | "not_authenticated" | "checking" | "error";export function App() {// Keep track of the user's authentication statusconst [state, setState] = React.useState<State>("checking");// Run the authentication check when the component mountsReact.useEffect(() => {checkAuthenticationStatus(auth).then((state) => {setState(state);});}, []);// Send a request to check if the user is authenticatedasync function checkAuthenticationStatus(): State {const auth = getAuthentication();try {const token = await auth.getCanvaUserToken();const response = await fetch("https://localhost:3001/authentication/check",{method: "POST",headers: {Authorization: `Bearer ${token}`,},});const body = await response.json();if (body?.isAuthenticated) {return "authenticated";} else {return "not_authenticated";}} catch (error) {console.error(error);return "error";}}return (<div>{state === "checking" && "Checking if authenticated"}{state === "authenticated" && "You are authenticated!"}{state === "not_authenticated" && "You are not authenticaed."}{state === "error" && "Something went wrong."}</div>);}