Skip to content

Authentication

Softly uses JWT-based authentication with a dual-token strategy: short-lived access tokens for API calls and long-lived refresh tokens for session persistence.

Token Strategy

TokenLifetimePurpose
Access token1 hourSent with every API request
Refresh token30 daysUsed to obtain new access tokens

Both tokens are issued on signup and login. The mobile app stores them in expo-secure-store (encrypted device storage).

Signup

Users register with email, name, and password (minimum 8 characters). The response includes both tokens and the full user object.

POST /api/v1/auth/signup

On success, the app stores both tokens and navigates to the onboarding flow.

Login

Standard email/password login. Tokens are returned in the same format as signup.

POST /api/v1/auth/login

Token Refresh

When an access token expires, the mobile app intercepts the 401 response and calls the refresh endpoint. If the refresh token is also expired, the user is logged out.

POST /api/v1/auth/refresh

The refresh flow is handled transparently by an Axios interceptor in services/api.ts. The user never sees a login screen unless their refresh token expires (30 days of inactivity).

Session Validation

The /me endpoint validates the current access token and returns the full user object including subscription tier, level data, and household info.

GET /api/v1/auth/me

The app calls this on launch to hydrate AuthContext and determine the correct navigation path (auth screens vs main tabs).

Password Reset

Password reset uses a deep link flow:

  1. User enters email on the forgot password screen
  2. Backend generates a time-limited token (Rails 8 generates_token_for) and sends it via email
  3. Email contains a deep link: softly://reset-password?token=...
  4. The app opens reset-password.tsx, which collects the new password and calls the API
  5. On success, the user gets new access + refresh tokens and is logged in

TIP

The forgot password endpoint always returns a success message, even if the email doesn't exist. This prevents email enumeration attacks.

Settings Update

Authenticated users can update their name, email, and family visibility toggle via:

PATCH /api/v1/auth/settings

Password changes require the current password to be sent alongside the new password.

Mobile Storage

Tokens are stored using expo-secure-store (wrapper in services/storage.ts), which uses the iOS Keychain and Android EncryptedSharedPreferences. Tokens are never stored in AsyncStorage or any unencrypted location.

Internal documentation — not for public distribution