@rpcbase/auth
v0.104.0
Published
UI helpers + API routes for authentication.
Downloads
2,904
Readme
@rpcbase/auth
UI helpers + API routes for authentication.
1) Register auth routes in your API
Example (like sample-app):
import { initApi } from "@rpcbase/api"
import { routes as authRoutes } from "@rpcbase/auth/routes"
const routes = {
...authRoutes,
...import.meta.glob("./**/handler.ts"),
}
export const runApi = async ({ app }) => {
await initApi({ app, routes })
}The OAuth request (state + PKCE verifier) is stored server-side in RBOAuthRequest (global model). A short-lived HttpOnly cookie binds state to the initiating browser (SameSite=None; Secure on HTTPS). The callback handler uses an Express session only to sign the user in.
2) Configure providers
Provider configuration is provided by the host app (server-side) at runtime.
Call configureOAuthProviders() before initializing your API routes:
import { initApi } from "@rpcbase/api"
import { configureOAuthProviders } from "@rpcbase/auth/oauth"
import { routes as authRoutes } from "@rpcbase/auth/routes"
configureOAuthProviders({
mock: {
issuer: "http://localhost:9400",
clientId: "rpcbase-sample-app",
scope: "openid email profile",
callbackPath: "/api/auth/oauth/mock/callback",
},
})
const routes = {
...authRoutes,
...import.meta.glob("./**/handler.ts"),
}
export const runApi = async ({ app }) => {
await initApi({ app, routes })
}The app is responsible for sourcing secrets (env, vault, etc.) and passing them to configureOAuthProviders().
Each provider must define a scope and a callbackPath so the generated redirect_uri matches your routing:
configureOAuthProviders({
google: {
issuer: "https://accounts.google.com",
clientId: process.env.GOOGLE_CLIENT_ID!,
scope: "openid email profile",
callbackPath: "/api/auth/oauth/google/callback",
},
})3) Start the OAuth flow from the client
window.location.assign("/api/auth/oauth/mock/start")You can optionally pass a return path:
window.location.assign("/api/auth/oauth/mock/start?returnTo=/app")Optional: declare OAuth routes yourself
If you don’t want to mount the full authRoutes, you can register the OAuth handlers manually:
import { createOAuthCallbackHandler, createOAuthStartHandler } from "@rpcbase/auth/oauth"
export default (api) => {
api.get("/api/auth/oauth/:provider/start", createOAuthStartHandler({
getAuthorizationParams: (providerId) =>
providerId === "apple"
? { response_mode: "form_post" }
: undefined,
}))
const callback = createOAuthCallbackHandler({
createUserOnFirstSignIn: false,
missingUserRedirectPath: "/auth/sign-up",
successRedirectPath: "/app",
})
api.get("/api/auth/oauth/:provider/callback", callback)
api.post("/api/auth/oauth/:provider/callback", callback)
}4) What happens on callback
On a successful callback:
- tokens are exchanged (
/token) - userinfo is fetched (when supported by the provider)
- the matching
RBUseris created on first-seen identity (and the OAuth credentials are saved underRBUser.oauthProviders[provider]) - the session is signed in, and the user is redirected to
/onboarding
If the callback handler is configured with createUserOnFirstSignIn: false and no matching user is found, it redirects to missingUserRedirectPath (when provided).
Apple (helper)
Apple requires a JWT clientSecret. You can generate it server-side:
import { createAppleClientSecret } from "@rpcbase/auth/oauth"Mock provider (dev/tests)
This repo uses oauth2-mock-server in sample-app/server.js to spin up a local OIDC provider for development and Playwright tests.
Notes:
oauth2-mock-serversimulates auth and immediately redirects back on/authorize(it does not provide a UI to pick an account).- Override the port with
RB_OAUTH_MOCK_SERVER_PORT(default9400)
