auth: seed portal as a stable public+PKCE OIDC client in migrate step
build / test (push) Successful in 7s
build / build (push) Successful in 9s

This commit is contained in:
2026-07-05 22:14:42 -04:00
parent 213a2b3583
commit 1a52fba596
2 changed files with 29 additions and 2 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ if (process.env.APPLE_CLIENT_ID && process.env.APPLE_CLIENT_SECRET) {
// Shares the MCP product's CNPG database. Better Auth's tables (user, session, // Shares the MCP product's CNPG database. Better Auth's tables (user, session,
// account, jwks, oauthApplication, ...) don't collide with the app's `users` // account, jwks, oauthApplication, ...) don't collide with the app's `users`
// table, so they coexist in the default schema — same DB, no second instance. // table, so they coexist in the default schema — same DB, no second instance.
const pool = new Pool({ export const pool = new Pool({
connectionString: required("AUTH_DATABASE_URL"), connectionString: required("AUTH_DATABASE_URL"),
}); });
+28 -1
View File
@@ -4,7 +4,7 @@
* the MCP server's Alembic step. Idempotent — a no-op once the schema is current. * the MCP server's Alembic step. Idempotent — a no-op once the schema is current.
*/ */
import { getMigrations } from "better-auth/db/migration"; import { getMigrations } from "better-auth/db/migration";
import { auth } from "./auth.js"; import { auth, pool } from "./auth.js";
const { toBeCreated, toBeAdded, runMigrations } = await getMigrations(auth.options); const { toBeCreated, toBeAdded, runMigrations } = await getMigrations(auth.options);
@@ -19,4 +19,31 @@ if (toBeCreated.length === 0 && toBeAdded.length === 0) {
console.log("better-auth schema applied"); console.log("better-auth schema applied");
} }
// Seed the portal as a stable public (PKCE) OIDC client. Better Auth hashes
// confidential secrets, so the portal uses PKCE with no secret. Idempotent.
const portalClientId = process.env.PORTAL_CLIENT_ID ?? "intervalsicu-portal";
const portalRedirect =
process.env.PORTAL_REDIRECT_URI ?? "https://intervalsicu.farhoodlabs.com/portal/auth/callback";
await pool.query(
`INSERT INTO "oauthClient"
(id, "clientId", "clientSecret", public, "requirePKCE", "tokenEndpointAuthMethod",
"redirectUris", "grantTypes", "responseTypes", scopes, type, "skipConsent", disabled,
name, "createdAt", "updatedAt")
VALUES ($1, $1, NULL, true, true, 'none',
$2::jsonb, $3::jsonb, $4::jsonb, $5::jsonb, 'web', true, false,
'Intervals.icu MCP portal', now(), now())
ON CONFLICT ("clientId") DO UPDATE SET
"redirectUris" = EXCLUDED."redirectUris", public = true, "requirePKCE" = true,
"tokenEndpointAuthMethod" = 'none', "skipConsent" = true, disabled = false,
"updatedAt" = now()`,
[
portalClientId,
JSON.stringify([portalRedirect]),
JSON.stringify(["authorization_code", "refresh_token"]),
JSON.stringify(["code"]),
JSON.stringify(["openid", "email", "profile"]),
],
);
console.log(`seeded portal OAuth client '${portalClientId}' (public + PKCE)`);
process.exit(0); process.exit(0);