Skip to main content

Overview

The AuthService handles all authentication operations including login, token refresh, logout, and fetching user profiles. It provides unified methods that work for both web (cookie-based) and mobile (token-based) authentication flows. Location: src/app/core/services/http/auth.service.ts

Base Configuration

private readonly baseUrl = environment.apiUrl;
All endpoints use the apiUrl from the environment configuration.

Methods

login()

Authenticates a user with email/phone and password.
login(
  payload: LoginPayload, 
  httpOptions?: { withCredentials?: boolean }
): Observable<LoginResponse>
payload
LoginPayload
required
Login credentials and configuration
httpOptions
object
Optional HTTP configuration
LoginResponse
object
Authentication response containing tokens

Usage Example

import { AuthService } from '@/app/core/services/http/auth.service';
import { UserType } from '@/app/core/models/user/user.auxiliary';

const authService = inject(AuthService);

// Mobile login
const loginPayload = {
  email: '[email protected]',
  password: 'securePassword123',
  appAudience: 'passenger_app' as const,
  expectedUserType: UserType.Passenger
};

authService.login(loginPayload).subscribe({
  next: (response) => {
    console.log('Access token:', response.accessToken);
    console.log('Refresh token:', response.refreshToken); // mobile only
    console.log('Expires at:', new Date(response.accessTokenExpiresAt));
  },
  error: (err: ApiError) => {
    console.error('Login failed:', err.message);
    if (err.validation) {
      console.error('Validation errors:', err.validation);
    }
  }
});

// Web login with cookies
authService.login(loginPayload, { withCredentials: true }).subscribe(...);

refresh()

Refreshes an expired access token. Supports both web (cookie) and mobile (token) flows.
refresh(
  refreshToken?: string, 
  useCookie = false
): Observable<RefreshResponse>
refreshToken
string
Refresh token (required for mobile flows, unused for web)
Set to true for web flows to use HttpOnly cookies
RefreshResponse
object
New authentication tokens

Usage Example

// Mobile refresh
const refreshToken = 'stored_refresh_token_here';
authService.refresh(refreshToken, false).subscribe({
  next: (response) => {
    console.log('New access token:', response.accessToken);
    console.log('New refresh token:', response.refreshToken);
    // Store new tokens
  },
  error: (err: ApiError) => {
    console.error('Refresh failed:', err.message);
    // Redirect to login
  }
});

// Web refresh (uses cookie)
authService.refresh(undefined, true).subscribe({
  next: (response) => {
    console.log('New access token:', response.accessToken);
    // Refresh token is in HttpOnly cookie
  },
  error: (err) => {
    // Session expired, redirect to login
  }
});

logoutWeb()

Logs out a web session (clears HttpOnly cookie).
logoutWeb(): Observable<void>

Usage Example

authService.logoutWeb().subscribe({
  next: () => {
    console.log('Logged out successfully');
    // Redirect to login page
  },
  error: (err: ApiError) => {
    console.error('Logout failed:', err.message);
  }
});

logoutMobile()

Logs out a mobile session by invalidating the refresh token.
logoutMobile(refreshToken: string): Observable<void>
refreshToken
string
required
The refresh token to invalidate

Usage Example

const refreshToken = 'stored_refresh_token';
authService.logoutMobile(refreshToken).subscribe({
  next: () => {
    console.log('Logged out successfully');
    // Clear stored tokens
  },
  error: (err: ApiError) => {
    console.error('Logout failed:', err.message);
  }
});

me()

Fetches the current user’s profile.
me(useCookie: boolean = true): Observable<UserProfile>
Whether to send credentials via cookie (true for web, false for mobile)
UserProfile
object
User profile data

Usage Example

// Web (with cookies)
authService.me(true).subscribe({
  next: (profile) => {
    console.log('User:', profile.name);
    console.log('Email:', profile.email);
    console.log('Type:', profile.userType);
    if (profile.currentLocation) {
      const [lng, lat] = profile.currentLocation.coordinates;
      console.log('Location:', lat, lng);
    }
  },
  error: (err: ApiError) => {
    console.error('Failed to fetch profile:', err.message);
  }
});

// Mobile (with Authorization header)
authService.me(false).subscribe(...);

Error Handling

All methods use consistent error handling that normalizes errors into the ApiError interface:
export interface ApiError {
  status?: number;              // HTTP status code
  message: string;              // Human-readable error message
  code?: string;                // Application error code
  validation?: Record<string, string[]>; // Field validation errors
  raw?: any;                    // Raw error response
  url?: string | null;          // Request URL
}

Error Handling Example

authService.login(payload).subscribe({
  next: (response) => { /* success */ },
  error: (err: ApiError) => {
    if (err.status === 401) {
      console.error('Invalid credentials');
    } else if (err.status === 422 && err.validation) {
      // Handle validation errors
      Object.entries(err.validation).forEach(([field, errors]) => {
        console.error(`${field}: ${errors.join(', ')}`);
      });
    } else if (err.status === 0) {
      console.error('Network error:', err.message);
    } else {
      console.error('Error:', err.message);
      if (err.code) console.error('Code:', err.code);
    }
  }
});

TypeScript Interfaces

LoginPayload

export interface LoginPayload {
  id?: string;
  email?: string;
  phoneNumber?: string;
  password: string;
  location?: Location;
  appAudience: AppAudience;         
  expectedUserType: UserType; 
}

type AppAudience = 'driver_app' | 'passenger_app' | 'admin_panel' | 'api_client';

LoginResponse

export interface BaseAuthResponse {
  accessToken: string;
  accessTokenExpiresAt: number;
  refreshTokenExpiresAt?: number;
  sid?: string;
  sessionType: SessionType;
}

export interface LoginResponseMobile extends BaseAuthResponse {
  refreshToken: string;
}

export interface LoginResponseWeb extends BaseAuthResponse {
  refreshToken?: never;
}

export type LoginResponse = LoginResponseMobile | LoginResponseWeb;

RefreshResponse

export interface RefreshResponseMobile extends BaseAuthResponse {
  refreshToken: string;
}

export interface RefreshResponseWeb extends BaseAuthResponse {
  refreshToken?: never;
}

export type RefreshResponse = RefreshResponseMobile | RefreshResponseWeb;

UserProfile

export interface UserProfile {
  id: string;
  name: string | null;
  email: string | null;
  phoneNumber?: string | null;
  profilePictureUrl?: string | null;
  userType: UserType;
  currentLocation?: {
    type: 'Point';
    coordinates: [number, number];
  } | null;
  createdAt?: string;
}

export enum UserType {
  Passenger = 'passenger',
  Driver = 'driver',
  Admin = 'admin',
}

API Response Wrapper

The backend wraps responses in a standard format:
interface ApiResponse<T> {
  success: boolean;
  message?: string;
  data: T;
}
The AuthService automatically unwraps the data field, so you receive the typed response directly.

Build docs developers (and LLMs) love