04
Product
16
Backend
09
Auth
12
iOS
07
Infra
02
Real-Time

Use environment-based auth manager with Apollo interceptors

ADR-0018 ACCEPTED · 2025-07-20
Environment-based auth service with Apollo interceptors

Context

The iOS app makes authenticated GraphQL requests via Apollo Client. Authentication needs to be transparent to views — they shouldn't manage tokens, handle 401s, or know about auth state transitions. SwiftUI's Environment pattern provides dependency injection, and Apollo's interceptor chain handles request-level concerns.

Decision

A single @MainActor @Observable AuthService injected at the app root via SwiftUI Environment. Apollo interceptors handle token injection and auth error recovery transparently.

AuthService responsibilities:

  • Owns auth state (unknown → unauthenticated → registered)
  • Persists tokens in secure storage (iOS Keychain)
  • Manages device ID for token binding
  • Provides login, logout, session checking
  • Clears Apollo cache on auth failure or logout

Apollo interceptors:

  • Auth interceptor adds Authorization: Bearer <token> and X-Device-ID headers to all requests
  • Error interceptor catches auth failures and triggers re-authentication

Views access AuthService via @Environment(AuthService.self) and make GraphQL calls normally. Auth happens behind the scenes.

Consequences

Clean view code — views focus on business logic, not token management. Auth state is a single source of truth. Interceptors handle the mechanical parts (headers, refresh, error recovery) without view involvement.

The trade-off is that auth logic is less visible, which can make debugging harder. The interceptor chain is also tightly coupled to Apollo's client architecture.