状态
Registry 状态:UNPUBLISHED。此 SDK 只能从仓库源码 checkout 安装;不要使用外部 package registry。
包状态为 当前包。Remix loader/action 认证辅助工具、cookie 会话集成和 OAuth callback 处理器已实现。在真实生产基础设施上的 IdP 往返验证仍待人工核实。
会话存储配置
// app/sessions.server.ts
import { createXidSessionStorage } from '@xid-kit/remix'
export const sessionStorage = createXidSessionStorage({
secret: process.env.SESSION_SECRET!, // required: cookie signing secret
// cookieName: '__xid_session', maxAge: 2592000, secure: true
})在 loader 中读取认证信息
getAuth 验证 Bearer token、显式应用 JWT cookie、可选同源 Core exchange 或已配置的 Remix session JWT,然后返回 AuthResult。requireAuth 在未认证时抛出重定向到 redirectPath 的 302 响应。
import { getAuth, requireAuth } from '@xid-kit/remix'
import { json, redirect } from '@remix-run/node'
import type { LoaderFunctionArgs } from '@remix-run/node'
import { sessionStorage } from '~/sessions.server'
const jwtKey = JSON.parse(process.env.XID_JWKS_PUBLIC_KEY!)
const authOptions = {
jwtKey,
sessionStorage,
sessionTokenExchange: { endpoint: '/v1/sessions/token' },
}
// Optional check
export async function loader({ request }: LoaderFunctionArgs) {
const auth = await getAuth(request, authOptions)
if (!auth.userId) return redirect('/login')
return json({ userId: auth.userId, orgId: auth.orgId })
}
// Guard: throws redirect automatically when unauthenticated
export async function protectedLoader({ request }: LoaderFunctionArgs) {
const auth = await requireAuth(request, authOptions, { redirectPath: '/login' })
return json({ userId: auth.userId })
}OAuth callback 处理器
handleCallback 校验 state 参数以防 CSRF,交换授权码,并返回带 Set-Cookie 的 Response。
// app/routes/auth.callback.ts
import { handleCallback } from '@xid-kit/remix'
import type { ActionFunctionArgs } from '@remix-run/node'
import { sessionStorage } from '~/sessions.server'
export async function action({ request }: ActionFunctionArgs) {
const result = await handleCallback(request, {
clientId: process.env.XID_CLIENT_ID!,
redirectUri: process.env.XID_REDIRECT_URI!,
sessionStorage,
defaultReturnTo: '/dashboard',
})
if (!result.ok) throw new Response(result.error, { status: 400 })
return result.response // 302 redirect + Set-Cookie
}客户端 provider(root.tsx)
import { XidProvider } from '@xid-kit/remix' // re-export from @xid-kit/react
import { Outlet } from '@remix-run/react'
export default function App() {
return (
<XidProvider
mode="oidc"
issuer="https://xid.dev"
clientId="client_abc123"
redirectUri="https://app.example.com/auth/callback"
>
<Outlet />
</XidProvider>
)
}Management API 客户端
import { xidClient } from '@xid-kit/remix'
const client = xidClient({ secretKey: process.env.XID_SECRET_KEY! })
export async function loader() {
const result = await client.getUser('user_abc')
if (!result.ok) throw new Response(result.error.message, { status: result.error.status })
return json(result.value)
}导出的 API
| 导出 | 类型 | 用途 |
|---|---|---|
createXidSessionStorage |
function | XID token 的 Remix cookie 会话存储 |
getAuth |
function | 验证 JWT 或会话 token;返回 AuthResult |
requireAuth |
function | 类似 getAuth,但在未认证时抛出重定向响应 |
handleCallback |
function | OAuth callback:校验 state,交换 code,设置会话 cookie |
xidClient |
function | 返回绑定到密钥的服务端 Management API 客户端 |
getTokenFromSession, setTokensInSession, clearTokensFromSession |
函数 | 用于自定义会话处理的底层 token 辅助工具 |
重新导出
重导出所有 @xid-kit/react 客户端组件和 hook,使 root.tsx 只需一次导入即可获得 provider 和客户端组件。
PKCE 和安全
- 公共客户端使用带 PKCE S256 的授权码。不存储客户端密钥。
handleCallback校验state参数与会话以防 CSRF。- 访问令牌存储在
HttpOnly会话 cookie 中,不会写入localStorage。