Skip to content

Conversation

@isadorable-png
Copy link
Collaborator

@isadorable-png isadorable-png commented Dec 22, 2025

🎯 Overview

This PR adds secure Figma design integration to Storybook, allowing developers to view Figma designs alongside component stories without exposing the Figma API token.

✨ Features Added
1. Secure Figma API Proxy (app/api/figma/route.ts)
Server-side API route that proxies Figma requests
Token stored only in server environment variables (FIGMA_TOKEN)
Built-in security features:
Rate limiting (30 requests/min per IP)
Input validation for file IDs
Response sanitization
CORS protection

2. Storybook Figma Helper (shared/utils/figma-storybook.ts)
getFigmaDesignConfig(url) - Easy-to-use function for story files
Reads token from server-side env vars at Storybook build time
Graceful fallback when token is not configured

3. Client-side Figma Utility (shared/utils/figma.ts)
fetchFigmaFile() - Fetch Figma data through the secure proxy
extractFileIdFromUrl() - Helper to parse Figma URLs
getFigmaProxyUrl() - Generate proxy URLs

4. Updated Story Files (12 files)
Added Figma design parameters to stories for:
Avatars (EnsAvatar)
Alerts (BannerAlert, InlineAlert)
Badges (BadgeStatus)
Buttons (Button, IconButton)
Links (DefaultLink, UnderlinedLink)
Layout (Footer, BlankSlate, DividerDefault, Table)
Sections (SectionTitle, SubSection, SubSectionContainer, SubSectionTitle)

5. Storybook Configuration
Updated .storybook/main.ts to load FIGMA_TOKEN from env
Added custom manager head and theme configuration

6. Security Scripts
scripts/check-token-security.js - Verifies no tokens are hardcoded
scripts/test-production-storybook.js - Tests production Storybook security
Unit tests for security (figma-security.test.ts)
API route tests (route.test.ts)

7. Documentation
FIGMA_SETUP.md - Complete setup guide
FIGMA_PROXY_IMPLEMENTATION.md - Technical implementation details
FIGMA_PRODUCTION_SECURITY.md - Security considerations

@vercel
Copy link

vercel bot commented Dec 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
anticapture Ready Ready Preview, Comment Jan 7, 2026 9:48pm
anticapture-storybook Ready Ready Preview, Comment Jan 7, 2026 9:48pm

Comment on lines 10 to 28
const envPath = resolve(__dirname, "../.env.local");
if (existsSync(envPath)) {
try {
const envFile = readFileSync(envPath, "utf-8");
envFile.split("\n").forEach((line) => {
const match = line.match(/^([^=:#]+)=(.*)$/);
if (match) {
const key = match[1]. trim();
const value = match[2].trim().replace(/^["']|["']$/g, "");
if (! process.env[key]) {
process.env[key] = value;
}
}
});
} catch (error) {
// Failed to parse .env.local, log quietly
console.info("ℹ️ Could not parse .env.local file");
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use dotenv instead

parameters: {
layout: "centered",
design: getFigmaDesignConfig(
"https://www.figma.com/design/DEKMQifA8YOb3oxznHboSY/%F0%9F%93%81-Orbit-UI?node-id=10150-19926",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use an env variable to avoid having to change multiple places

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file

FIGMA_SETUP.md Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file

stories: [
"../stories/**/*.mdx",
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
"../stories/**/*. stories.@(js|jsx|mjs|ts|tsx)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the space between ". stories" because it will break

Comment on lines 71 to 94
// Inject FIGMA_TOKEN into browser bundle for Storybook addon-designs
if (process.env. FIGMA_TOKEN) {
// Token exists - inject it into the bundle
const webpack = require("webpack");
config.plugins = config.plugins || [];
config.plugins.push(
new webpack.DefinePlugin({
"process.env.FIGMA_TOKEN": JSON.stringify(process.env.FIGMA_TOKEN),
})
);
console.log("✅ FIGMA_TOKEN injetado no bundle do Storybook");
} else {
// Token not found - warn the user
console.warn(
"⚠️ FIGMA_TOKEN não encontrado. Integração com Figma não funcionará no Storybook."
);
console.warn(
" Para desenvolvimento local: adicione FIGMA_TOKEN ao arquivo apps/dashboard/.env.local"
);
console.warn(
" Para Vercel (preview/production): adicione FIGMA_TOKEN nas Environment Variables do projeto"
);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of these logs and warn, a single warn saying "FIGMA_TOKEN not found" is okay but please use en-US

Comment on lines +158 to +161
const rateLimited = responses.some(
(r) => r.status === 429 || r.status === 200,
);
expect(rateLimited).toBe(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will always be true

use this instead:

const has429 = responses.some((r) => r.status === 429);
expect(has429).toBe(true);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really dont think those 3 scripts are necessary, the figma api token security follow the same pattern as other api tokens that we have, no need of 3 scripts to validate it

parameters: {
layout: "fullwidth",
design: getFigmaDesignConfig(
"https://www.figma.com/design/DEKMQifA8YOb3oxznHboSY/%F0%9F%93%81-Orbit-UI?node-id=10150-19926",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this url to .env

parameters: {
layout: "centered",
design: getFigmaDesignConfig(
"https://www.figma.com/design/DEKMQifA8YOb3oxznHboSY/%F0%9F%93%81-Orbit-UI?node-id=10166-18044",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, add it to .env


// eslint-disable-next-line no-restricted-imports
import { getFigmaDesignConfig } from "./figma-storybook";
// eslint-disable-next-line no-restricted-imports
Copy link
Contributor

@brunod-e brunod-e Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove every reference of eslint-disable in this code because it mask potential errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants