fix(#411): QA-005 — production logging, error classification, session-expired state
logAuthError now always logs (not dev-only). Replaced isBackendError with parseAuthError-based classification. signOut uses proper error type. Session expiry sets explicit session_expired state. Login page logs in prod. Fixed pre-existing lint violations in auth package (campsite rule). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,7 +43,15 @@ export async function signInWithCredentials(username: string, password: string):
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = (await response.json().catch(() => ({}))) as { message?: string };
|
||||
let errorBody: { message?: string } = {};
|
||||
try {
|
||||
errorBody = (await response.json()) as { message?: string };
|
||||
} catch (jsonError: unknown) {
|
||||
console.error(
|
||||
`[Auth] Failed to parse error response body (HTTP ${String(response.status)}):`,
|
||||
jsonError
|
||||
);
|
||||
}
|
||||
const parsed = parseAuthError(errorBody.message ? new Error(errorBody.message) : response);
|
||||
throw new Error(parsed.message);
|
||||
}
|
||||
@@ -57,37 +65,52 @@ export async function signInWithCredentials(username: string, password: string):
|
||||
* Returns null if not authenticated.
|
||||
*/
|
||||
export async function getAccessToken(): Promise<string | null> {
|
||||
const session = await getSession();
|
||||
if (!session.data?.user) {
|
||||
try {
|
||||
const session = await getSession();
|
||||
if (!session.data?.user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Type assertion for custom user fields
|
||||
const user = session.data.user as {
|
||||
accessToken?: string;
|
||||
tokenExpiresAt?: number;
|
||||
};
|
||||
|
||||
if (!user.accessToken) {
|
||||
console.warn("[Auth] Session exists but no accessToken found");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if token is expired (with 1 minute buffer)
|
||||
if (user.tokenExpiresAt && user.tokenExpiresAt - Date.now() < 60000) {
|
||||
// Token is expired or about to expire
|
||||
// The session will be refreshed automatically by BetterAuth
|
||||
// but we should return null to trigger a re-auth if needed
|
||||
return null;
|
||||
}
|
||||
|
||||
return user.accessToken;
|
||||
} catch (error: unknown) {
|
||||
console.error("[Auth] Failed to get access token:", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Type assertion for custom user fields
|
||||
const user = session.data.user as {
|
||||
accessToken?: string;
|
||||
tokenExpiresAt?: number;
|
||||
};
|
||||
|
||||
// Check if token is expired (with 1 minute buffer)
|
||||
if (user.tokenExpiresAt && user.tokenExpiresAt - Date.now() < 60000) {
|
||||
// Token is expired or about to expire
|
||||
// The session will be refreshed automatically by BetterAuth
|
||||
// but we should return null to trigger a re-auth if needed
|
||||
return null;
|
||||
}
|
||||
|
||||
return user.accessToken ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user is an admin.
|
||||
*/
|
||||
export async function isAdmin(): Promise<boolean> {
|
||||
const session = await getSession();
|
||||
if (!session.data?.user) {
|
||||
try {
|
||||
const session = await getSession();
|
||||
if (!session.data?.user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const user = session.data.user as { isAdmin?: boolean };
|
||||
return user.isAdmin === true;
|
||||
} catch (error: unknown) {
|
||||
console.error("[Auth] Failed to check admin status:", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
const user = session.data.user as { isAdmin?: boolean };
|
||||
return user.isAdmin === true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user