← 返回 Skills 市场
dyagil

Magic Link Bridge

作者 dyagil · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
51
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install dyagil-magic-link-bridge
功能描述
Generate Supabase magic-links that land directly on a custom portal subpath (e.g. `/portal/`) instead of being silently rewritten to the project Site URL by...
使用说明 (SKILL.md)

Magic-Link Bridge (token_hash flow)

Problem This Solves

Supabase's standard magic-link flow:

  1. Server calls auth.admin.generate_link({ type: 'magiclink', email, options: { redirect_to: 'https://site/portal/' } }).
  2. Customer clicks the resulting https://\x3Cref>.supabase.co/auth/v1/verify?... URL.
  3. Supabase verifies, then 302-redirects to redirect_to with #access_token=\x3Cjwt>&type=magiclink in the URL fragment.

This breaks in two real-world scenarios:

  • Redirect not whitelisted. If https://site/portal/ is not in the project's Redirect URL allow-list, Supabase silently rewrites the redirect to the Site URL (https://site/). The customer lands on the marketing homepage with a hash full of tokens — and your portal code never sees them.
  • WhatsApp / Instagram / FB Messenger in-app browsers. WebViews routinely strip URL fragments across navigations, so even when the redirect IS whitelisted the tokens vanish before your JS can read them.

Fix

Don't go through Supabase's /auth/v1/verify endpoint at all. Generate the link manually so it lands directly on the portal page, then have the portal exchange the token via auth.verifyOtp({ token_hash, type }).

The final link looks like:

https://site/portal/?token_hash=\x3Chashed_token>&type=magiclink

hashed_token comes from the same admin/generate_link response — Supabase returns it alongside action_link.

Server (API endpoint)

// POST /api/send-portal-link  (Vercel serverless or any backend)
const gen = await fetch(
  `${SUPABASE_URL}/auth/v1/admin/generate_link`,
  {
    method: 'POST',
    headers: {
      apikey: SUPABASE_SERVICE_ROLE_KEY,
      Authorization: 'Bearer ' + SUPABASE_SERVICE_ROLE_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ type: 'magiclink', email: customer.email }),
  }
).then(r => r.json());

const u = new URL('https://site/portal/');
u.searchParams.set('token_hash', gen.hashed_token);
u.searchParams.set('type',       gen.verification_type || 'magiclink');
const magicLink = u.toString();

// Send magicLink via WhatsApp / SMS / email. The portal page handles the rest.

Keep a fallback to gen.action_link if hashed_token is missing — some older Supabase auth versions don't return it.

Client (portal page)

The portal page must:

  1. Detect ?token_hash=...&type=... on load.
  2. Call verifyOtp({ token_hash, type }).
  3. Strip the params from the URL (they're single-use; a refresh would replay them).
  4. Handle ?error=... / ?error_description=... with a friendly alert.

See scripts/portal-bridge.js for a drop-in snippet.

The Supabase client itself should be configured with:

window.supabase.createClient(URL, ANON_KEY, {
  auth: {
    persistSession: true,
    autoRefreshToken: true,
    detectSessionInUrl: true,   // picks up hash-fragment flows automatically
    flowType: 'pkce',           // ?code=... flow as well
    storageKey: 'site-portal-auth',
  },
});

Why Also Keep a Bridge in /index.html?

Even after deploying this skill, an older email/SMS may still hold a Supabase-style verify URL that was minted before the fix. Add a safety net at the site root that detects either #access_token= (hash flow) or ?code=/?error= (PKCE / error redirects) and forwards to /portal/. See scripts/index-redirect.js.

Testing

  1. Generate a link as admin (curl with service_role).
  2. Open it headless (curl / Playwright) and confirm it lands on /portal/ with the user logged in (Supabase session present in localStorage).
  3. If the page shows #access_token=... on the homepage instead — the bridge in index.html is missing or stale, not this server-side fix.

Common Pitfalls

  • One-time tokens replay on refresh. Always strip the query params after verifyOtp succeeds, with history.replaceState. Otherwise refreshing the page tries to verify a now-expired token and shows an error.
  • PKCE state must match. flowType: 'pkce' requires the same browser to generate and consume the code — so ?code= flows only work when the link is opened in the same browser that initiated the auth. Magic links opened in a different browser must use the token_hash path (default).
  • Hash + query both present. When forwarding from index.html, concatenate as '/portal/' + window.location.search + window.location.hash so neither half is lost.
安全使用建议
Use this skill only if you are intentionally implementing a Supabase portal magic-link flow. Keep the service-role key on the backend, protect the link-generation endpoint, and confirm the portal strips token parameters before analytics or other third-party scripts can observe them.
功能分析
Type: OpenClaw Skill Name: dyagil-magic-link-bridge Version: 1.0.0 The skill bundle provides a legitimate utility for handling Supabase magic-link authentication flows, specifically addressing issues with URL fragment stripping in mobile in-app browsers. The included scripts (index-redirect.js and portal-bridge.js) perform standard URL parameter parsing and redirection to ensure authentication tokens reach the intended application subpath, with no evidence of malicious intent, data exfiltration, or prompt injection.
能力标签
cryptorequires-sensitive-credentials
能力评估
Purpose & Capability
The stated purpose, SKILL.md instructions, and included JavaScript all align around Supabase magic-link handling for a portal subpath. The capability is security-sensitive because it creates and consumes login links.
Instruction Scope
The instructions are user-directed snippets rather than automatic execution. They do not show hidden behavior, but the backend endpoint example should be implemented with authentication, authorization, and rate limiting.
Install Mechanism
There is no package install, remote download, shell command, or dependency setup. The skill provides documentation plus two small drop-in JavaScript files.
Credentials
Use of Supabase URL, anon key, and service-role key is proportionate to generating Supabase magic links, but the registry metadata does not declare credentials even though the documentation requires them for implementation.
Persistence & Privilege
The client configuration enables normal Supabase browser session persistence and token refresh. This is expected for a portal login flow, but the service-role key must remain server-side and out of browser code.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install dyagil-magic-link-bridge
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /dyagil-magic-link-bridge 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release
元数据
Slug dyagil-magic-link-bridge
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Magic Link Bridge 是什么?

Generate Supabase magic-links that land directly on a custom portal subpath (e.g. `/portal/`) instead of being silently rewritten to the project Site URL by... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 51 次。

如何安装 Magic Link Bridge?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install dyagil-magic-link-bridge」即可一键安装,无需额外配置。

Magic Link Bridge 是免费的吗?

是的,Magic Link Bridge 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Magic Link Bridge 支持哪些平台?

Magic Link Bridge 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Magic Link Bridge?

由 dyagil(@dyagil)开发并维护,当前版本 v1.0.0。

💬 留言讨论