Sessions

Mushu uses JWT tokens for authentication. This page covers token lifecycle, refresh handling, and session management.

What This Is

When a user signs in, Mushu creates a session and issues two tokens: an access token (short-lived) and a refresh token (long-lived). The access token is used for API requests, and the refresh token is used to get new access tokens when they expire.

Token Lifetimes

TokenLifetimeUse
Access Token 1 hour API requests (Authorization header)
Refresh Token 30 days Getting new access tokens

Refreshing Tokens

CLI

mushu auth refresh

API

POST /auth/refresh
Content-Type: application/json

{
  "access_token": "expired_access_token",
  "refresh_token": "your_refresh_token"
}

Response:

{
  "tokens": {
    "access_token": "new_access_token",
    "refresh_token": "new_refresh_token"
  },
  "user": {
    "user_id": "...",
    "email": "..."
  }
}

Note: Refresh returns a new refresh token. Store it to replace the old one. The old refresh token is invalidated.

Validating Tokens

Check if a token is valid and get user info:

GET /auth/validate
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
  "valid": true,
  "user_id": "...",
  "user_type": "apple",
  "email": "..."
}

Handling Expiration in iOS

Implement automatic token refresh in your app:

class TokenManager {
    private var accessToken: String?
    private var refreshToken: String?

    func getValidToken() async throws -> String {
        if let token = accessToken, !isExpired(token) {
            return token
        }

        // Token expired, refresh it
        guard let refresh = refreshToken else {
            throw AuthError.notAuthenticated
        }

        let newTokens = try await refreshTokens(using: refresh)
        self.accessToken = newTokens.accessToken
        self.refreshToken = newTokens.refreshToken

        return newTokens.accessToken
    }

    private func isExpired(_ token: String) -> Bool {
        // Decode JWT and check exp claim
        // Return true if expired or expiring soon (e.g., < 5 min)
    }
}

Logging Out

CLI

mushu auth logout

API

POST /auth/logout
Content-Type: application/json

{
  "access_token": "...",
  "refresh_token": "..."
}

Logout invalidates both tokens server-side. Even if someone has the tokens, they will no longer work.

Multi-Device Sessions

Each device/client gets its own session. Logging out on one device doesn't affect sessions on other devices. Each session has independent tokens.

FAQ

What happens if my refresh token expires?

The user must sign in again with Apple. There's no way to extend a refresh token after it expires.

Can I revoke all sessions?

Not currently. Each session must be logged out individually. Contact support if you need to revoke all sessions for a user.

Why did my token stop working?

Common reasons:

  • Access token expired (refresh it)
  • Refresh token expired (sign in again)
  • User was removed from an organization
  • User revoked Apple Sign In access

How do I know when to refresh?

Decode the JWT and check the exp claim. Refresh when the token is expired or about to expire (e.g., less than 5 minutes remaining). Alternatively, refresh when you get a 401 response.