fix: toAuthErrorShape() ignored backend error.code, session-expired screen unreachable
Known bug per BACKEND-API-REFERENCE.md §5: the client has dedicated session-expired/invalid-signature recovery screens fully built, but the mapper only ever derived the error code from HTTP status, never the response body - so a real 401 with error.code: 'TOKEN_EXPIRED' rendered the generic 'Unauthorized' screen instead. Frontend half of the fix: prefer error.code from the body when present (mapped via authErrorCodeFromBackendCode), fall back to status-derived code otherwise. Stays dormant until the backend actually sends the code, per the doc. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,24 @@ export interface AuthError {
|
|||||||
status?: number;
|
status?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the backend error envelope's `error.code` (see
|
||||||
|
* BACKEND-API-REFERENCE.md §5) to the client's AuthErrorCode screens.
|
||||||
|
* Only codes with a dedicated screen are mapped; anything else falls back
|
||||||
|
* to the HTTP-status-derived code via authErrorCodeFromStatus.
|
||||||
|
*/
|
||||||
|
const BACKEND_ERROR_CODE_MAP: Record<string, AuthErrorCode> = {
|
||||||
|
TOKEN_EXPIRED: 'session-expired',
|
||||||
|
INVALID_SIGNATURE: 'invalid-signature',
|
||||||
|
UNAUTHENTICATED: 'unauthorized',
|
||||||
|
FORBIDDEN: 'forbidden',
|
||||||
|
SERVICE_UNAVAILABLE: 'backend-unavailable',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function authErrorCodeFromBackendCode(code: unknown): AuthErrorCode | undefined {
|
||||||
|
return typeof code === 'string' ? BACKEND_ERROR_CODE_MAP[code] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/** Maps a backend HTTP status to the AuthErrorCode screen it should route to. */
|
/** Maps a backend HTTP status to the AuthErrorCode screen it should route to. */
|
||||||
export function authErrorCodeFromStatus(status: number): AuthErrorCode {
|
export function authErrorCodeFromStatus(status: number): AuthErrorCode {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http';
|
|||||||
import { catchError, switchMap, tap, throwError } from 'rxjs';
|
import { catchError, switchMap, tap, throwError } from 'rxjs';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AuthTokenPair } from '../models/auth-api.model';
|
import { AuthTokenPair } from '../models/auth-api.model';
|
||||||
import { AuthError, authErrorCodeFromStatus } from '../models/auth-error.model';
|
import { AuthError, authErrorCodeFromBackendCode, authErrorCodeFromStatus } from '../models/auth-error.model';
|
||||||
import { AuthApiService } from './auth-api.service';
|
import { AuthApiService } from './auth-api.service';
|
||||||
import { Ed25519KeypairService } from './ed25519-keypair.service';
|
import { Ed25519KeypairService } from './ed25519-keypair.service';
|
||||||
import { SessionService } from './session.service';
|
import { SessionService } from './session.service';
|
||||||
@@ -109,7 +109,9 @@ export class AuthService {
|
|||||||
|
|
||||||
private toAuthErrorShape(error: unknown, fallbackCode: AuthError['code']): AuthError {
|
private toAuthErrorShape(error: unknown, fallbackCode: AuthError['code']): AuthError {
|
||||||
if (error instanceof HttpErrorResponse) {
|
if (error instanceof HttpErrorResponse) {
|
||||||
return { code: authErrorCodeFromStatus(error.status), message: error.message, status: error.status };
|
const bodyCode = (error.error as { error?: { code?: unknown } } | null)?.error?.code;
|
||||||
|
const code = authErrorCodeFromBackendCode(bodyCode) ?? authErrorCodeFromStatus(error.status);
|
||||||
|
return { code, message: error.message, status: error.status };
|
||||||
}
|
}
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
return { code: fallbackCode, message: error.message };
|
return { code: fallbackCode, message: error.message };
|
||||||
|
|||||||
Reference in New Issue
Block a user