Checking a user's authentication status

How to check if a user is authenticated.

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:

  1. Copy the ID of an app from the Your apps page.

  2. In the starter kit's .env file, set CANVA_APP_ID to the ID of the app.

  3. 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 user
console.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 user
const userId = response.locals.userId;
// Load the database
const data = await db.read();
// Check if the user is authenticated
const isAuthenticated = data.users.includes(userId);
// Return the authentication status
response.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 status
const [state, setState] = React.useState<State>("checking");
// Run the authentication check when the component mounts
React.useEffect(() => {
checkAuthenticationStatus(auth).then((state) => {
setState(state);
});
}, []);
// Send a request to check if the user is authenticated
async 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>
);
}