fix(auth): stop wiki login loop to coming-soon and surface non-member state
Some checks failed
Test / vitest (push) Failing after 6m9s
Test / playwright (push) Has been skipped
Test / visual (push) Has been skipped
Test / Notify on failure (push) Successful in 2s

Members (and pre-registrants) hitting wiki.ghostguild.org were getting bounced
to /coming-soon with a "Pre-Register" link, even when the OIDC flow was
working correctly.

- Allowlist /auth/oidc-error, /auth/logout-confirm, /auth/logout-success,
  and /verify in the coming-soon middleware so OIDC errors and main-site
  magic links stop redirecting to the pre-register page.
- Raise OIDC Interaction TTL from 10m to 15m so it outlives the magic-link
  JWT and legitimate members don't hit expired-interaction errors when they
  click the email a few minutes late.
- Differentiate the "email isn't a registered member" response on the wiki
  login route and show a dedicated "Not a member yet" state with a
  pre-register link and contact email, instead of the misleading
  "Check your inbox" that silently failed.
This commit is contained in:
Jennie Robinson Faber 2026-04-15 17:55:55 +01:00
parent 2394248d53
commit 1e9e9c4d97
4 changed files with 70 additions and 22 deletions

View file

@ -28,12 +28,9 @@ export default defineEventHandler(async (event) => {
});
}
const GENERIC_MESSAGE =
"If this email is registered, we've sent a login link.";
const member = await (Member as any).findOne({ email });
if (!member) {
return { success: true, message: GENERIC_MESSAGE };
return { success: true, registered: false };
}
const config = useRuntimeConfig(event);
@ -62,7 +59,7 @@ ${baseUrl}/oidc/interaction/verify?token=${token}
This link expires in 15 minutes. If you didn't request this, you can safely ignore this email.`,
});
return { success: true, message: GENERIC_MESSAGE };
return { success: true, registered: true };
} catch (error) {
console.error("Failed to send OIDC login email:", error);
throw createError({

View file

@ -81,7 +81,7 @@ export async function getOidcProvider() {
AuthorizationCode: 600, // 10 minutes
RefreshToken: 14 * 24 * 60 * 60, // 14 days
Session: 14 * 24 * 60 * 60, // 14 days
Interaction: 600, // 10 minutes
Interaction: 900, // 15 minutes — must match magic-link JWT TTL so the interaction outlives the token
Grant: 14 * 24 * 60 * 60, // 14 days
},