Add forward auth portal — CPM as built-in IdP replacing Authentik
CPM can now act as its own forward auth provider for proxied sites. Users authenticate at a login portal (credentials or OAuth) and Caddy gates access via a verify subrequest, eliminating the need for external IdPs like Authentik. Key components: - Forward auth flow: verify endpoint, exchange code callback, login portal - User groups with membership management - Per-proxy-host access control (users and/or groups) - Caddy config generation for forward_auth handler + callback route - OAuth and credential login on the portal page - Admin UI: groups page, inline user/group assignment in proxy host form - REST API: /api/v1/groups, /api/v1/forward-auth-sessions, per-host access - Integration tests for groups and forward auth schema Also fixes mTLS E2E test selectors broken by the RBAC refactor. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
app/api/forward-auth/callback/route.ts
Normal file
37
app/api/forward-auth/callback/route.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { redeemExchangeCode } from "@/src/lib/models/forward-auth";
|
||||
|
||||
const COOKIE_NAME = "_cpm_fa";
|
||||
const COOKIE_MAX_AGE = 7 * 24 * 60 * 60; // 7 days
|
||||
|
||||
/**
|
||||
* Forward auth callback — redeems an exchange code and sets the session cookie.
|
||||
* Caddy routes /.cpm-auth/callback on proxied domains to this endpoint.
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
const code = request.nextUrl.searchParams.get("code");
|
||||
if (!code) {
|
||||
return new NextResponse("Missing code parameter", { status: 400 });
|
||||
}
|
||||
|
||||
const result = await redeemExchangeCode(code);
|
||||
if (!result) {
|
||||
return new NextResponse(
|
||||
"Invalid or expired authorization code. Please try logging in again.",
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// Redirect back to original URL with the session cookie set
|
||||
const response = NextResponse.redirect(result.redirectUri, 302);
|
||||
|
||||
response.cookies.set(COOKIE_NAME, result.rawSessionToken, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "lax",
|
||||
maxAge: COOKIE_MAX_AGE
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
Reference in New Issue
Block a user