Skip to content

Connect Figma (Callback)

Method

This API follows the REST methodology.

HTTP Method

GET: Receive Figma's redirect after an admin authorizes the app, exchange the authorization code, and store the grant.

Figma redirects the admin's browser here. It is not called by the plugin or by any client of ours.

Naming Convention

To ensure consistency and readability, JSON nodes in responses use camelCase.

Request and Response

Headers

Request Headers

None required โ€” see Authentication.

Response Headers

  • Content-Type

Callback

URI

GET /api/v1/figma-oauth/callback

The path has no {organization_id} segment: redirect_uri must exactly match a URL registered on the Figma app, so it is fixed. The organization travels inside state instead.

Query Parameters

Name Type Required Description
code string Optional The authorization code. Absent when the admin declined. Expires 30 seconds after issue.
state string Required The signed token minted by authorize. Carries the organization.
error string Optional Present when the admin declined in Figma.

Response

The response is JSON (HTTP status: 200 OK).

{
  "organizationId": 1,
  "connected": true,
  "message": "Figma connected. The scheduler will refresh this organization grant automatically."
}

Response Fields

Name Type Description
organizationId integer The organization the grant was stored for, read from state.
connected boolean Always true on success.
message string Human-readable confirmation for the browser tab.

Tokens are never returned to the caller and never logged.

Authentication

None โ€” and there cannot be any. This is a browser redirect from Figma, so it carries no Cognito token and protectedRoute cannot gate it.

state is therefore the entire security boundary: it is server-minted by an authenticated org admin, HMAC-signed, organization-bound, single-purpose and 10-minute-lived, and its signature is compared in constant time. The organization is read from the signed payload, never from anything the caller supplies.

Without that, anyone who could reach this URL could bind their own Figma grant to your organization โ€” handing themselves whatever the scheduler can read.

Signature-failure and malformed-input both return the same message, so the endpoint is not an oracle for forging attempts.

Error Handling

Description Status Code Status Name
The admin declined in Figma, or no code was returned 400 Bad Request
Figma rejected the code (it expires after 30 seconds โ€” start again) 400 Bad Request
state is invalid, tampered with, or expired 401 Unauthorized
Encrypting or storing the grant failed 500 Internal Server Error

Processing Flow

  1. If error is present, the admin declined โ€” report it and stop.
  2. Verify state: constant-time signature check, expiry check, and recover organizationId from the signed payload.
  3. Exchange code at https://api.figma.com/v1/oauth/token using HTTP Basic client_id:client_secret. The Admin API holds the client secret.
  4. Encrypt the access and refresh tokens with the platform ENCRYPTION_KEY, then upsert the organization's figma_oauth_grant row in PostgreSQL.
  5. Log which Figma account authorized (audit only) and return the confirmation.

Afterwards

Nothing further is required. When wf2des needs Figma access, it calls the Admin API's IAM-protected internal token provider. The Admin API returns the existing access token or refreshes it under a PostgreSQL advisory lock, then returns only the access token and expiry. The worker calls Figma with Authorization: Bearer.

A human is needed again only if the grant is revoked in Figma, the service account is deactivated, the client secret is rotated, or the encryption key is rotated.