fix(auth): prevent login page freeze on OAuth sign-in failure (#506)
All checks were successful
ci/woodpecker/push/api Pipeline was successful
ci/woodpecker/push/web Pipeline was successful

Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #506.
This commit is contained in:
2026-02-25 01:59:36 +00:00
committed by jason.woltje
parent 9a7673bea2
commit 5f6c520a98
3 changed files with 37 additions and 6 deletions

View File

@@ -254,6 +254,10 @@ export function createAuth(prisma: PrismaClient) {
enabled: true,
},
plugins: [...getOidcPlugins()],
logger: {
disabled: false,
level: "error",
},
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days absolute max
updateAge: 60 * 60 * 2, // 2 hours — minimum session age before BetterAuth refreshes the expiry on next request

View File

@@ -123,6 +123,14 @@ export class AuthController {
try {
await handler(req, res);
// BetterAuth writes responses directly — catch silent 500s that bypass NestJS error handling
if (res.statusCode >= 500) {
this.logger.error(
`BetterAuth returned ${String(res.statusCode)} for ${req.method} ${req.url} from ${clientIp}` +
` — check container stdout for '# SERVER_ERROR' details`
);
}
} catch (error: unknown) {
const message = error instanceof Error ? error.message : String(error);
const stack = error instanceof Error ? error.stack : undefined;

View File

@@ -128,12 +128,31 @@ function LoginPageContent(): ReactElement {
setError(null);
const callbackURL =
typeof window !== "undefined" ? new URL("/", window.location.origin).toString() : "/";
signIn.oauth2({ providerId, callbackURL }).catch((err: unknown) => {
const message = err instanceof Error ? err.message : String(err);
console.error(`[Auth] OAuth sign-in initiation failed for ${providerId}:`, message);
setError("Unable to connect to the sign-in provider. Please try again in a moment.");
setOauthLoading(null);
});
signIn
.oauth2({ providerId, callbackURL })
.then((result) => {
// BetterAuth returns Data | Error union — check for error or missing redirect URL
const hasError = "error" in result && result.error;
const hasUrl = "data" in result && result.data?.url;
if (hasError || !hasUrl) {
const errObj = hasError ? result.error : null;
const message =
errObj && typeof errObj === "object" && "message" in errObj
? String(errObj.message)
: "no redirect URL";
console.error(`[Auth] OAuth sign-in failed for ${providerId}:`, message);
setError("Unable to connect to the sign-in provider. Please try again in a moment.");
setOauthLoading(null);
}
// If data.url exists, BetterAuth's client will redirect the browser automatically.
// No need to reset loading — the page is navigating away.
})
.catch((err: unknown) => {
const message = err instanceof Error ? err.message : String(err);
console.error(`[Auth] OAuth sign-in initiation failed for ${providerId}:`, message);
setError("Unable to connect to the sign-in provider. Please try again in a moment.");
setOauthLoading(null);
});
}, []);
const handleCredentialsLogin = useCallback(