Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Set up Canva Connect API OAuth 2.0 PKCE authentication and project scaffolding. Use when creating a new Canva integration, setting up OAuth credentials, or initializing a Canva Connect API project. Trigger with phrases like "install canva", "setup canva", "canva auth", "configure canva API", "canva OAuth".
.claude/skills/jeremylongshore-canva-install-auth/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 52% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 0% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 95% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 101% | 0% |
Build authorization as a stateful backend protocol, not a copied token snippet. Keep the PKCE verifier and client secret out of the browser and serialize refresh-token replacement per user.
Configure name, minimum scopes, at least one controlled redirect URI, and secret storage. Remove localhost and loopback redirect hosts from production configuration.
Generate high-entropy per-request state and a PKCE verifier that meets Canva's documented character/length rules. Store both server-side with short expiry and one-time use.
Use Canva's authorization endpoint, S256 challenge method, explicit space-separated scopes, client ID, state, and an exactly registered redirect URI.
Reject missing/mismatched/expired state, repeated codes, unexpected redirect context, and errors before token exchange.
Authenticate the token request using the approved client method, send the verifier and authorization code, validate the response, encrypt access and refresh tokens separately, and discard transient secrets.
Single-flight refresh per user because each refresh token is single-use. Commit the new access token, expiry, and replacement refresh token atomically; reauthorize on unrecoverable failure.
Revoke when required, delete application-held tokens and cached authorization, and record a credential-free receipt.
Canva Connect calls use Bearer access tokens obtained by a backend through OAuth 2.0 Authorization Code with SHA-256 PKCE. Request explicit least-privilege scopes, keep client secrets and tokens out of browser-visible state, and serialize refresh so the replacement single-use refresh token is stored atomically.
Use Read and Grep for discovery and evidence. Use Write or Edit only for the approved artifact, code, configuration, test, or receipt described by this workflow; do not make an unapproved Canva-side change.
A callback consumes a one-time state record and server-held verifier, exchanges the code on the backend, and stores the replacement refresh token in the same transaction that invalidates the prior token.
| Failure | Response | | --- | --- | | State mismatch | Stop the flow and create no token record | | Verifier missing | Restart authorization; never weaken PKCE | | Refresh race detected | Serialize by Canva user and retain one authoritative result | | Scope added later | Update portal configuration and obtain fresh user consent |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 10,368 | 6,431 | -38% | 1 | 1 | 0% | 2,042 | 3,111 | +52% | 0 | 0 | — |
case-02 | pass→pass | 7,480 | 3,352 | -55% | 1 | 1 | 0% | 1,250 | 2,443 | +95% | 0 | 0 | — |
case-03 | pass→pass | 7,911 | 4,939 | -38% | 1 | 1 | 0% | 1,327 | 2,667 | +101% | 0 | 0 | — |
case-08 | pass→pass | 4,613 | 2,935 | -36% | 1 | 1 | 0% | 726 | 2,308 | +218% | 0 | 0 | — |
case-04 | pass→pass | 11,295 | 6,663 | -41% | 1 | 1 | 0% | 2,235 | 3,150 | +41% | 0 | 0 | — |
case-05 | pass→pass | 9,348 | 4,924 | -47% | 1 | 1 | 0% | 1,802 | 2,815 | +56% | 0 | 0 | — |
case-06 | pass→pass | 11,876 | 7,808 | -34% | 1 | 1 | 0% | 2,372 | 3,440 | +45% | 0 | 0 | — |
case-07 | pass→pass | 4,333 | 3,010 | -31% | 1 | 1 | 0% | 725 | 2,281 | +215% | 0 | 0 | — |
case-09 | pass→pass | 5,026 | 3,712 | -26% | 1 | 1 | 0% | 823 | 2,253 | +174% | 0 | 0 | — |
case-10 | pass→pass | 6,132 | 1,533 | -75% | 1 | 1 | 0% | 984 | 2,039 | +107% | 0 | 0 | — |
case-11 | pass→pass | 5,145 | 2,999 | -42% | 1 | 1 | 0% | 814 | 2,210 | +171% | 0 | 0 | — |
case-12 | fail→pass | 11,475 | 1,421 | -88% | 1 | 1 | 0% | 1,970 | 1,973 | +0% | 0 | 0 | — |
case-13 | pass→pass | 4,529 | 2,659 | -41% | 1 | 1 | 0% | 675 | 2,247 | +233% | 0 | 0 | — |
case-14 | fail→pass | 8,000 | 1,808 | -77% | 1 | 1 | 0% | 1,387 | 2,031 | +46% | 0 | 0 | — |
case-15 | pass→pass | 11,715 | 9,699 | -17% | 1 | 1 | 0% | 2,093 | 3,571 | +71% | 0 | 0 | — |
case-16 | pass→pass | 9,787 | 9,304 | -5% | 1 | 1 | 0% | 1,700 | 3,580 | +111% | 0 | 0 | — |
case-17 | pass→pass | 7,248 | 3,553 | -51% | 1 | 1 | 0% | 1,272 | 2,391 | +88% | 0 | 0 | — |
case-18 | pass→pass | 5,561 | 2,310 | -58% | 1 | 1 | 0% | 827 | 2,196 | +166% | 0 | 0 | — |
case-19 | pass→pass | 5,068 | 2,932 | -42% | 1 | 1 | 0% | 802 | 2,257 | +181% | 0 | 0 | — |
case-20 | pass→pass | 15,125 | 10,420 | -31% | 1 | 1 | 0% | 2,674 | 4,079 | +53% | 0 | 0 | — |
case-21 | pass→pass | 15,359 | 15,329 | -0% | 1 | 1 | 0% | 2,953 | 4,744 | +61% | 0 | 0 | — |
case-22 | pass→pass | 14,706 | 12,731 | -13% | 1 | 1 | 0% | 2,839 | 4,585 | +62% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
The publisher has shipped newer versions since this run, so these numbers describe v1, not the version currently listed.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.