fix(auth): prevent login page freeze on OAuth sign-in failure #506
@@ -254,6 +254,10 @@ export function createAuth(prisma: PrismaClient) {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
plugins: [...getOidcPlugins()],
|
plugins: [...getOidcPlugins()],
|
||||||
|
logger: {
|
||||||
|
disabled: false,
|
||||||
|
level: "error",
|
||||||
|
},
|
||||||
session: {
|
session: {
|
||||||
expiresIn: 60 * 60 * 24 * 7, // 7 days absolute max
|
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
|
updateAge: 60 * 60 * 2, // 2 hours — minimum session age before BetterAuth refreshes the expiry on next request
|
||||||
|
|||||||
@@ -123,6 +123,14 @@ export class AuthController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await handler(req, res);
|
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) {
|
} catch (error: unknown) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
const stack = error instanceof Error ? error.stack : undefined;
|
const stack = error instanceof Error ? error.stack : undefined;
|
||||||
|
|||||||
@@ -128,12 +128,31 @@ function LoginPageContent(): ReactElement {
|
|||||||
setError(null);
|
setError(null);
|
||||||
const callbackURL =
|
const callbackURL =
|
||||||
typeof window !== "undefined" ? new URL("/", window.location.origin).toString() : "/";
|
typeof window !== "undefined" ? new URL("/", window.location.origin).toString() : "/";
|
||||||
signIn.oauth2({ providerId, callbackURL }).catch((err: unknown) => {
|
signIn
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
.oauth2({ providerId, callbackURL })
|
||||||
console.error(`[Auth] OAuth sign-in initiation failed for ${providerId}:`, message);
|
.then((result) => {
|
||||||
setError("Unable to connect to the sign-in provider. Please try again in a moment.");
|
// BetterAuth returns Data | Error union — check for error or missing redirect URL
|
||||||
setOauthLoading(null);
|
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(
|
const handleCredentialsLogin = useCallback(
|
||||||
|
|||||||
Reference in New Issue
Block a user