Every first Microsoft login failed with 403 "Only superusers can perform this action": PocketBase applies the collection createRule to the automatic record creation during OAuth2 sign-up, and team_members was created with createRule null (superuser-only) on the wrong assumption that the OAuth2 flow bypasses it. Since the pre-Azure records were deliberately dropped, every user was a first login and nobody could get in. Reproduced locally against a mock OIDC provider (PocketBase v0.30.4). createRule becomes '@request.context = "oauth2"': record creation is allowed exclusively from within the OAuth2 flow. Anonymous REST creates (which could otherwise pre-seed rogue admin profiles) remain rejected — covered by an explicit test. - pb_migrations/1781000002_allow_oauth2_signup.js: applies the rule on already-migrated environments (Labs); idempotent, guarded, with down - pb_migrations/1781000000_team_members_to_auth.js: same rule for fresh environments (filename unchanged — ledger-safe) - scripts/setup-pb-collections.mjs: fallback entry mirrored - docs/auth-spec.md: ADR 009 + files table Verified with a mock-OIDC matrix (9/9): baseline reproduces the 403 on the old rule; upgrade path heals (first login 200, role/enrollment/name defaults, second login no duplicate, anonymous create still rejected); fresh chain + admin allow-list mapping OK. DoD harness regression 15/15, npm test 112/112. Closes #22 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
1.6 KiB
JavaScript
47 lines
1.6 KiB
JavaScript
/// <reference path="../pb_data/types.d.ts" />
|
|
//
|
|
// Issue #22 — Allow OAuth2 sign-up on team_members.
|
|
//
|
|
// The collection was created with `createRule: null` on the assumption that
|
|
// the OAuth2 flow bypasses it. It does not: PocketBase applies the createRule
|
|
// to the automatic record creation on a first OIDC login, so every first
|
|
// login failed with 403 "Only superusers can perform this action". Since the
|
|
// pre-Azure records were intentionally dropped, EVERY user was a first login
|
|
// and nobody could sign in.
|
|
//
|
|
// `@request.context = "oauth2"` scopes record creation to the OAuth2 flow
|
|
// only — plain REST creates (e.g. anonymous POST /records, which could
|
|
// otherwise pre-seed rogue admin profiles) keep being rejected.
|
|
//
|
|
// Environments that have not applied 1781000000 yet get this rule directly
|
|
// from that (updated) migration; this follow-up exists for databases where it
|
|
// already ran with the old `null` rule (Labs). Applying it twice is harmless.
|
|
migrate((app) => {
|
|
let col;
|
|
try {
|
|
col = app.findCollectionByNameOrId("team_members");
|
|
} catch (_) {
|
|
console.log("allow_oauth2_signup: team_members does not exist — skipping.");
|
|
return;
|
|
}
|
|
if (col.type !== "auth") {
|
|
console.log("allow_oauth2_signup: team_members is not an auth collection — skipping.");
|
|
return;
|
|
}
|
|
col.createRule = '@request.context = "oauth2"';
|
|
app.save(col);
|
|
}, (app) => {
|
|
// Down: restore the (broken) superuser-only rule.
|
|
let col;
|
|
try {
|
|
col = app.findCollectionByNameOrId("team_members");
|
|
} catch (_) {
|
|
return;
|
|
}
|
|
if (col.type !== "auth") {
|
|
return;
|
|
}
|
|
col.createRule = null;
|
|
app.save(col);
|
|
});
|