← スキル一覧に戻る

workos-integration
by ADLenehan
Safe hosting for the non-technical
⭐ 0🍴 0📅 2026年1月13日
SKILL.md
name: workos-integration description: Patterns for WorkOS SSO integration in Battery. Use this skill when implementing authentication, organization management, directory sync, or session handling.
WorkOS Integration Patterns
Overview
Battery uses WorkOS for:
- SSO federation (customers connect their Okta/Azure AD)
- Organization management (multi-tenancy)
- Directory sync (user provisioning)
SDK Setup
import { WorkOS } from '@workos-inc/node'
const workos = new WorkOS(process.env.WORKOS_API_KEY!)
SSO Authentication
Authorization URL
// Generate SSO login URL
async function getAuthorizationUrl(
organizationId: string,
redirectUri: string
) {
const authorizationUrl = workos.sso.getAuthorizationUrl({
organization: organizationId,
redirectUri,
clientId: process.env.WORKOS_CLIENT_ID!,
})
return authorizationUrl
}
Handle Callback
// app/api/auth/callback/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const code = request.nextUrl.searchParams.get('code')
if (!code) {
return NextResponse.redirect('/login?error=missing_code')
}
try {
const { profile } = await workos.sso.getProfileAndToken({
code,
clientId: process.env.WORKOS_CLIENT_ID!,
})
// Create session, set cookies, etc.
// profile contains: id, email, firstName, lastName, organizationId
return NextResponse.redirect('/dashboard')
} catch (error) {
return NextResponse.redirect('/login?error=auth_failed')
}
}
Organization Management
Create Organization
async function createOrganization(name: string, domains: string[]) {
const org = await workos.organizations.createOrganization({
name,
allowProfilesOutsideOrganization: false,
domains,
})
return org
}
List Organizations
async function listOrganizations() {
const { data: organizations } = await workos.organizations.listOrganizations({
limit: 100,
})
return organizations
}
Get Organization
async function getOrganization(orgId: string) {
return workos.organizations.getOrganization(orgId)
}
SSO Connection Setup
List Connections
async function getOrgConnections(organizationId: string) {
const { data: connections } = await workos.sso.listConnections({
organizationId,
})
return connections
}
Admin Portal Link
Generate a link for IT admins to configure SSO:
async function getAdminPortalLink(organizationId: string) {
const { link } = await workos.portal.generateLink({
organization: organizationId,
intent: 'sso', // or 'dsync' for directory sync
returnUrl: `${process.env.APP_URL}/settings/sso`,
})
return link
}
Directory Sync
List Directory Users
async function listDirectoryUsers(directoryId: string) {
const { data: users } = await workos.directorySync.listUsers({
directory: directoryId,
})
return users
}
Webhook Events
Handle directory sync webhooks:
// app/api/webhooks/workos/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
const payload = await request.text()
const sigHeader = request.headers.get('workos-signature')!
const webhook = workos.webhooks.constructEvent({
payload,
sigHeader,
secret: process.env.WORKOS_WEBHOOK_SECRET!,
})
switch (webhook.event) {
case 'dsync.user.created':
await handleUserCreated(webhook.data)
break
case 'dsync.user.deleted':
await handleUserDeleted(webhook.data)
break
case 'dsync.group.user_added':
await handleUserAddedToGroup(webhook.data)
break
}
return NextResponse.json({ received: true })
}
Session Management
Session Token
interface BatterySession {
userId: string
email: string
organizationId: string
role: 'admin' | 'member'
expiresAt: number
}
// Create session after SSO callback
async function createSession(profile: Profile): Promise<string> {
const session: BatterySession = {
userId: profile.id,
email: profile.email,
organizationId: profile.organizationId,
role: await getUserRole(profile.id, profile.organizationId),
expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
}
return signJWT(session)
}
Middleware
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifySession } from '@/lib/auth'
export async function middleware(request: NextRequest) {
const session = await verifySession(request)
if (!session) {
return NextResponse.redirect(new URL('/login', request.url))
}
// Add session to request headers for server components
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-battery-user-id', session.userId)
requestHeaders.set('x-battery-org-id', session.organizationId)
return NextResponse.next({
request: { headers: requestHeaders },
})
}
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*'],
}
Auth Gateway Pattern
Battery wraps deployed apps with an auth proxy:
// Deployed app requests flow through Battery auth gateway
// 1. User hits {app}.{org}.battery.app
// 2. Battery checks for valid session cookie
// 3. If no session, redirect to WorkOS SSO
// 4. After SSO, set session cookie and proxy to Vercel app
interface AuthGatewayConfig {
appId: string
organizationId: string
allowedRoles?: string[]
}
Key Patterns
- Organization-first: Always scope operations to an organization
- Admin Portal: Let IT admins self-service SSO setup
- Webhook reliability: Use idempotency keys, handle retries
- Session security: Short-lived tokens, secure cookies
- Role mapping: Map IdP groups to Battery roles via directory sync
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です