| name | canva-local-dev-loop |
| description | Configure Canva Connect API local development with hot reload and mock server.
Use when setting up a development environment, testing OAuth flows locally,
or establishing a fast iteration cycle for Canva integrations.
Trigger with phrases like "canva dev setup", "canva local development",
"canva dev environment", "develop with canva", "canva mock".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*), Bash(pnpm:*), Grep |
| version | 1.5.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| tags | ["saas","design","canva"] |
| compatibility | Designed for Claude Code |
Canva Local Dev Loop
Overview
Set up a fast local development environment for Canva Connect API integrations with a token management server, mock API for testing, and hot reload.
Prerequisites
- Completed
canva-install-auth setup
- Node.js 18+ with npm/pnpm
- ngrok or similar tunnel for OAuth callbacks (or use localhost with Canva dev settings)
Instructions
Step 1: Project Structure
my-canva-app/
├── src/
│ ├── canva/
│ │ ├── client.ts # REST client wrapper (from canva-sdk-patterns)
│ │ ├── auth.ts # OAuth PKCE flow
│ │ └── types.ts # API response types
│ ├── routes/
│ │ ├── auth.ts # OAuth callback handler
│ │ └── designs.ts # Design CRUD routes
│ └── index.ts
├── tests/
│ ├── canva-mock.ts # Mock Canva API server
│ └── designs.test.ts
├── .env.local # Local secrets (git-ignored)
├── .env.example # Template for team
├── package.json
└── tsconfig.json
Step 2: Environment Setup
CANVA_CLIENT_ID=
CANVA_CLIENT_SECRET=
CANVA_REDIRECT_URI=http://localhost:3000/auth/canva/callback
PORT=3000
cp .env.example .env.local
Step 3: OAuth Callback Server
import express from 'express';
import { generatePKCE, getAuthorizationUrl, exchangeCodeForToken } from '../canva/auth';
const router = express.Router();
const pkceStore = new Map<string, string>();
router.get('/auth/canva/start', (req, res) => {
const { verifier, challenge } = generatePKCE();
const state = crypto.();
pkceStore.(state, verifier);
url = ({
: process..!,
: process..!,
: [, , , ],
: challenge,
state,
});
res.(url);
});
router.(, (req, res) => {
{ code, state } = req. { : ; : };
verifier = pkceStore.(state);
(!verifier) res.().();
pkceStore.(state);
tokens = ({
code,
: verifier,
: process..!,
: process..!,
: process..!,
});
.(, tokens., );
res.();
});