Skip to content

@xid-kit/remix

Remix loader and action server helpers, cookie session storage, and OAuth callback handler with React SDK re-exports.

Status

Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.

Package status is Current package. Remix loader/action auth helpers, cookie session integration, and OAuth callback handler are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.

Session storage setup

// 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
})

Reading auth in loaders

getAuth verifies a Bearer token, explicit application JWT cookie, optional same-origin Core exchange, or the configured Remix session JWT, then returns an AuthResult. requireAuth throws a 302 redirect to redirectPath when unauthenticated.

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 handler

handleCallback validates the state parameter to prevent CSRF, exchanges the authorization code, and returns a Response with Set-Cookie.

// 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
}

Client 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 client

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)
}

Exported API

Export Kind Purpose
createXidSessionStorage function Remix cookie session storage for XID tokens
getAuth function Verify JWT or session token; returns AuthResult
requireAuth function Like getAuth but throws a redirect response when unauthenticated
handleCallback function OAuth callback: validates state, exchanges code, sets session cookie
xidClient function Returns a server-side Management API client bound to the secret key
getTokenFromSession, setTokensInSession, clearTokensFromSession functions Low-level token helpers for custom session handling

Re-exports

Re-exports all @xid-kit/react client components and hooks. root.tsx needs only one import for both provider and client components.

PKCE and security

  • Public clients use Authorization Code with PKCE S256. No client secret is stored.
  • handleCallback validates the state parameter against the session to prevent CSRF.
  • Access tokens are stored in HttpOnly session cookies; they are never written to localStorage.
Navigation

Type to search...

Use arrow keys to navigateEnter to selectEscape to close