Zum Inhalt springen

Benutzerdefinierte Auth-Adapter

Rebase bringt eine eigene Authentifizierung mit – konfigurieren Sie sie hier. Diese Seite behandelt den anderen Fall: einen Identity-Provider, den Sie bereits betreiben oder für den Sie bereits bezahlen.

Rebase ermöglicht den vollständigen Austausch des integrierten Authentifizierungssystems über eine modulare Authentifizierungsarchitektur. Dies entkoppelt die Authentifizierungsprüfung von der Datenbank sowie den REST/WebSocket-Schichten und ermöglicht eine nahtlose Integration mit externen Anbietern wie Clerk, Auth0, Firebase Auth oder benutzerdefinierten JWT-Identitätsdiensten.

Sie können das AuthAdapter-Interface für vollständige Kontrolle direkt implementieren. Die Interface-Definition sieht wie folgt aus:

import { Hono } from "hono";
import type { HonoEnv } from "@rebasepro/server";
import { AuthenticatedUser, AuthAdapterCapabilities, UserManagementAdapter, UserCreationPrepareResult, UserCreationFinalizeResult } from "@rebasepro/types";
export interface AuthAdapter {
/** Unique identifier for this auth adapter (e.g., "clerk", "custom") */
readonly id: string;
/**
* Verifies an incoming HTTP request and returns the authenticated user payload.
* Called by Hono authentication middleware on every REST endpoint.
*/
verifyRequest(request: Request): Promise<AuthenticatedUser | null>;
/**
* Verifies a raw token string (e.g. for WebSocket connection handshake phase 1).
* If omitted, a synthetic request is automatically constructed.
*/
verifyToken?(token: string): Promise<AuthenticatedUser | null>;
/** Optional user management operations (CRUD) for the panel */
userManagement?: UserManagementAdapter;
/** Optional: Mount adapter-specific custom public routes (e.g. callback paths) */
createAuthRoutes?(): Hono<any, any, any> | undefined;
/** Optional: Mount adapter-specific admin-only routes */
createAdminRoutes?(): Hono<any, any, any> | undefined;
/** Advertise supported capabilities (to customize what the panel shows) */
getCapabilities(): AuthAdapterCapabilities | Promise<AuthAdapterCapabilities>;
/** Lifecycle hooks called during backend start and graceful shutdown */
initialize?(): Promise<void>;
destroy?(): Promise<void>;
/** Custom user lifecycle hooks (e.g., hash passwords before collection writes) */
prepareUserCreation?(
values: Record<string, unknown>,
collectionAuth?: unknown
): Promise<UserCreationPrepareResult>;
finalizeUserCreation?(
entity: { id: string; values: Record<string, unknown> },
clearPassword?: string
): Promise<UserCreationFinalizeResult>;
/** Static service key to bypass checks for server-to-server calls */
serviceKey?: string;
}

Unabhängig vom gewählten externen Authentifizierungsanbieter muss Ihr Adapter erfolgreiche Token-Verifizierungen in ein einheitliches AuthenticatedUser-Objekt auflösen. Der Rebase RLS Scope Injector bildet diese Werte innerhalb von Transaktionen direkt auf PostgreSQL-Sitzungsvariablen ab:

export interface AuthenticatedUser {
uid: string; // Maps to pg local 'app.user_id' -> rebase.uid()
email: string; // User email address
displayName?: string | null; // Optional display name
photoUrl?: string | null; // Optional avatar URL
roles: string[]; // Maps to pg local 'app.user_roles' -> rebase.roles()
isAdmin: boolean; // Grants global superuser privileges if true
rawToken?: string; // The original token string (for downstream forwarding)
claims?: Record<string, any>; // Custom claims/metadata (available in rebase.jwt())
}

Schnelle Integration über createCustomAuthAdapter

Abschnitt betitelt „Schnelle Integration über createCustomAuthAdapter“

Für Standardszenarien (wie die Validierung von JWTs eines Drittanbieterdienstes) können Sie das Hilfsprogramm createCustomAuthAdapter verwenden. Dieses Utility übernimmt Standardwerte für Capabilities und implementiert die WebSocket-Token-Validierung standardmäßig (out-of-the-box), indem es Ihre verifyRequest-Implementierung umschließt.

Um ein Rebase-Backend mit Clerk zu verbinden, können Sie Clerk-JWT-Tokens mithilfe des JSON Web Key Sets (JWKS) von Clerk verifizieren:

import { initializeRebaseBackend } from "@rebasepro/server";
import { createCustomAuthAdapter } from "@rebasepro/server";
import { createRemoteJWKSet, jwtVerify } from "jose";
// Clerk JWKS URL
const CLERK_JWKS_URL = "https://clerk.your-domain.com/.well-known/jwks.json";
const JWKS = createRemoteJWKSet(new URL(CLERK_JWKS_URL));
const clerkAuthAdapter = createCustomAuthAdapter({
serviceKey: process.env.REBASE_SERVICE_KEY,
verifyRequest: async (request) => {
const authHeader = request.headers.get("Authorization");
const token = authHeader?.replace("Bearer ", "");
if (!token) return null;
try {
// Verify Clerk JWT token against JWKS
const { payload } = await jwtVerify(token, JWKS);
const metadata = payload.metadata as Record<string, unknown> | undefined;
const roles = Array.isArray(metadata?.roles) ? metadata.roles as string[] : [];
return {
uid: payload.sub!,
email: (payload as Record<string, unknown>).email as string || "",
displayName: (payload as Record<string, unknown>).name as string || null,
roles: roles,
isAdmin: roles.includes("admin"),
claims: payload as Record<string, unknown>
};
} catch (error) {
console.error("Clerk token verification failed:", error);
return null; // Fail-closed
}
},
capabilities: {
hasBuiltInAuthRoutes: false, // Login is managed by Clerk UI
emailPasswordLogin: false,
registrationEnabled: false,
passwordReset: false,
profileUpdate: false,
sessionManagement: false
}
});
const backend = await initializeRebaseBackend({
auth: clerkAuthAdapter,
// ...
});

So verifizieren Sie Firebase Auth-Tokens mit den öffentlichen Zertifikaten von Firebase:

import { initializeRebaseBackend } from "@rebasepro/server";
import { createCustomAuthAdapter } from "@rebasepro/server";
import { createRemoteJWKSet, jwtVerify } from "jose";
const FIREBASE_JWKS_URL = "https://www.googleapis.com/robot/v1/metadata/jwk/securetoken@system.gserviceaccount.com";
const JWKS = createRemoteJWKSet(new URL(FIREBASE_JWKS_URL));
const FIREBASE_PROJECT_ID = "my-firebase-project-id";
const firebaseAuthAdapter = createCustomAuthAdapter({
serviceKey: process.env.REBASE_SERVICE_KEY,
verifyRequest: async (request) => {
const authHeader = request.headers.get("Authorization");
const token = authHeader?.replace("Bearer ", "");
if (!token) return null;
try {
const { payload } = await jwtVerify(token, JWKS, {
issuer: `https://securetoken.google.com/${FIREBASE_PROJECT_ID}`,
audience: FIREBASE_PROJECT_ID
});
const roles = Array.isArray((payload as Record<string, unknown>).roles) ? (payload as Record<string, unknown>).roles as string[] : [];
return {
uid: payload.sub!,
email: (payload as Record<string, unknown>).email as string || "",
displayName: (payload as Record<string, unknown>).name as string || null,
photoUrl: (payload as Record<string, unknown>).picture as string || null,
roles: roles,
isAdmin: roles.includes("admin"),
claims: payload as Record<string, unknown>
};
} catch (error) {
console.error("Firebase token verification failed:", error);
return null;
}
}
});
const backend = await initializeRebaseBackend({
auth: firebaseAuthAdapter,
// ...
});

Wenn Ihr benutzerdefinierter Auth-Provider das Einbinden von Weiterleitungsendpunkten erfordert (wie OAuth-Callback-Routen oder SAML-Login-Schleifen), implementieren Sie die Methode createAuthRoutes in Ihrem Adapter:

const myOauthAdapter: AuthAdapter = {
id: "custom-oauth",
verifyRequest: async (req) => ({
// validate the token, then return the caller
uid: "…",
email: "user@example.com",
roles: [],
isAdmin: false
}),
getCapabilities: () => ({
hasBuiltInAuthRoutes: true,
emailPasswordLogin: false,
registrationEnabled: false,
passwordReset: false,
adminPasswordReset: false,
sessionManagement: false,
profileUpdate: false,
emailVerification: false,
magicLink: false,
anonymousLogin: false,
enabledProviders: []
}),
createAuthRoutes: () => {
const app = new Hono<HonoEnv>();
// Mounted automatically under /api/auth/callback
app.get("/callback", async (c) => {
const code = c.req.query("code");
// Exchange code for provider tokens and set cookies/redirect
return c.redirect("/dashboard");
});
return app;
}
};

Wenn Sie CRUD-Operationen für Benutzer direkt im Panel ermöglichen möchten, implementieren Sie den userManagement-Helper innerhalb der Adapter-Optionen, der Hooks für listUsers, createUser, updateUser und deleteUser bereitstellt.