Skip to main content

Overview & Concepts

Authentication in social.plus

social.plus uses a dual authentication approach to ensure both application security and user verification:

API Key

Purpose: Identifies your application to social.plus servers
Scope: Application-level authentication
Usage: Required for SDK initialization
Security: Keep secure, never expose in client code

Auth Token

Purpose: Server-to-server verification that the user is validated by your backend
Scope: User-level authentication with your system
Usage: Optional for development, required for production
Security: Generated by your backend, proves user is legitimate

How Auth Tokens Work

Auth tokens enable server-to-server communication between social.plus and your backend:
1

User Authentication

Your app authenticates the user with your own authentication system (login, OAuth, etc.)
2

Backend Token Generation

Your backend server generates an auth token for the verified user and sends it to your app. Learn how to implement this →
3

social.plus Verification

When your app logs into social.plus, the auth token proves to social.plus that your backend has verified this user
4

Secure Communication

social.plus can now trust that this user session is legitimate and validated by your system
Why Auth Tokens? This approach ensures that only users who have been properly authenticated by your backend can access social.plus features, maintaining security and preventing unauthorized access.

When Do You Need Each?

// Production mode - API key + auth tokens
const client = Client.createClient({
  apiKey: 'your-prod-api-key',
  region: 'sg'
});

// Secure login with auth token from your backend
await client.login({
  userId: 'user-123',
  displayName: 'John Doe',
  authToken: 'token-generated-by-your-backend' // Proves user is verified by your system
});
Auth tokens must be generated by your secure backend after verifying the user. This ensures server-to-server trust between social.plus and your authentication system.

Quick Start (Basic Authentication)

Step 1: Initialize the SDK

Start by setting up the social.plus client with your API key:
let client = try! AmityClient(apiKey: "your-api-key", region: .SG)

Step 2: Login User

Authenticate users to access social.plus features:
Task { @MainActor in
    do {
        try await client.login(
            userId: "user-123",
            displayName: "John Doe",
            authToken: "your-auth-token", // Optional for development
            sessionHandler: sessionHandler
        )
        print("Login successful")
    } catch {
        print("Login failed: \(error)")
    }
}

Step 3: Check Authentication Status

Verify if a user is currently logged in:
if (client.sessionState == .established) {
    let currentUserId = client.getCurrentUserId()
    print("Current user: \(currentUserId)")
} else {
    // Proceed to social.plus Authentication
    authenticateToSocialPlus()
}

Step 4: Logout

End the user session: For an extra layer of security, which ensures accessToken revocation prior to performing logout(). Should the SDK fail to revoke the accessToken, the SDK will not proceed to logout and will throw an exception to notify the failure.
do {
    try await client.secureLogout()
} catch {
    /// Handle error from revoking accessToken here
}

Understanding Session States

Session states indicate what’s happening with user authentication. social.plus SDK automatically manages these states according to the flow shown in the diagram below:

notLoggedIn

Ready for login - user needs to authenticate
Entry points: App start (no session), logout, login failure

establishing

Login in progress - authentication being processed
Entry point: When login() is called from notLoggedIn state

established

Fully authenticated - SDK ready, all features available
Entry points: Successful login, successful token renewal

tokenExpired

Token renewal needed - automatic renewal attempted
Entry point: When auth token expires during established state

terminated

Session forcibly ended - user banned or deleted
Entry points: User banned/deleted from established or tokenExpired states

Session Flow

Understanding the complete session state flow helps you build responsive apps:
1

SDK Initialization

App starts: Always begins in the start state, then immediately moves to:
  • No saved session: Moves to notLoggedIn state
  • Has saved session: Moves to established state (if session valid)
2

Login Process

User attempts login:
  • notLoggedInestablishing (login in progress)
  • Login succeeds: establishingestablished
  • Login fails: establishingnotLoggedIn
3

Active Session Management

During active use in established state:
  • Token expires: establishedtokenExpired
  • Token renewed successfully: tokenExpiredestablished
  • User banned/deleted: establishedterminated
  • Manual logout: establishednotLoggedIn
4

Token Expiration Handling

When in tokenExpired state:
  • Auto-renewal succeeds: Returns to established state
  • Auto-renewal fails: User may need to re-authenticate
  • User banned during renewal: Moves to terminated state
  • Manual logout: Moves to notLoggedIn state
5

Session Termination

From terminated state:
  • Only way out is through logout → notLoggedIn
  • User must re-authenticate to access features again
Session state diagram image temporarily removed while the asset is unavailable. The textual flow description above preserves the full logic.

Observing Session State

Monitor session state changes to handle authentication in your app:
var cancellable: AnyCancellable?
// Observe session state changes
cancellable = client.$sessionState.sink { sessionState in
    switch sessionState {
    case .notLoggedIn:
        // Show login screen
        self?.showLogin()
    case .establishing:
        // Show loading indicator
        self?.showLoading()
    case .established:
        // Hide loading indicator, proceed to app
        self?.hideLoading()
        self?.proceedToApp()
    case .tokenExpired:
        // Attempt to refresh token (Optional)
        self?.showTokenRefreshIndicator()
    case .terminated:
        // Handle session termination
        self?.handleTermination()
    }
}

Advanced Session Management

For production apps, you’ll need sophisticated session handling with automatic token refresh:

Session Handlers for Token Refresh

Session handlers automatically manage token lifecycle:
class ProductionSessionHandler: AmitySessionHandler {
    func sessionWillRenewAccessToken(renewal: AccessTokenRenewal) {
        // Call your backend to get a fresh token
        AuthService.shared.refreshToken { result in
            switch result {
            case .success(let newToken):
                renewal.renewWithAuthToken(withAuthToken: newToken)
            case .failure(let error):
                print("Token refresh failed: \(error)")
                renewal.unableToRetrieveAuthToken()
            }
        }
    }
}

// Use during login
let sessionHandler = ProductionSessionHandler()
try await client.login(
    userId: userId,
    displayName: displayName,
    authToken: authToken,
    sessionHandler: sessionHandler
)

Alternative: Login with Access Token

By default, social.plus SDK handles access token management for you — you provide a userId and an optional authToken, and the SDK takes care of obtaining and refreshing access tokens behind the scenes. Login with Access Token is an alternative authentication method for customers who want to manage the entire token lifecycle themselves. Instead of letting the SDK obtain tokens, your backend issues a JWT access token directly, and your app passes it to the SDK.
Most developers should use the default login flow described in the Quick Start section above. Only use this approach if you have a specific need listed below.

When to Use This

SSO Integration

Your app already has a centralized authentication system and you want social.plus sessions to be issued as part of that flow — no extra network hop from the client.

Reduce Client-Side Dependencies

You want to eliminate the client-to-social.plus token exchange during login so that social.plus API availability does not block your app’s core login experience.

Default Login vs. Access Token Login

Default LoginLogin with Access Token
SDK methodlogin(userId, authToken)loginWithAccessToken(accessToken)
Who obtains the access token?The SDK handles it automaticallyYour backend issues a JWT and your app passes it to the SDK
Token renewalSession handler (sessionWillRenewAccessToken)Access token handler (onTokenRenew)
Best forMost integrationsSSO, custom auth backends, decoupled architectures
Client-to-social.plus call during login?Yes — SDK exchanges credentials for a tokenNo — token is pre-issued by your backend

How It Works

Implementation

Integration requires three steps: implement a token handler, register it, then login.
1

Implement an Access Token Handler

Create a handler that the SDK will call whenever the token needs renewal. Your handler should request a fresh JWT from your backend.
2

Register the Handler

Call setAccessTokenHandler() before logging in. This tells the SDK how to obtain a new token when the current one expires.
3

Login with Your Access Token

Call loginWithAccessToken() with the JWT your backend issued. The SDK verifies it with social.plus and establishes the session.
// 1. Implement the AccessTokenHandler protocol.
//    The SDK calls `onTokenRenew` when the access token is expired
//    or about to expire. You must return a fresh JWT obtained from
//    your own authentication backend.
class MyTokenHandler: AccessTokenHandler {
    func onTokenRenew(userId: String) async throws -> String {
        // Use the provided userId to request a new JWT
        // from your authentication backend.
        let newToken = try! await fetchNewTokenFromBackend(userId: userId)
        return newToken
    }
}

// 2. Register the handler BEFORE calling loginWithAccessToken.
//    The handler must be set first so the SDK can invoke it
//    whenever a token renewal is needed.
let client = try! AmityClient(apiKey: "<api-key>")
let tokenHandler = MyTokenHandler()
client.setAccessTokenHandler(tokenHandler)

// 3. Now login with the initial access token.
//    On subsequent token renewals, the SDK will automatically
//    call onTokenRenew and re-authenticate using the returned JWT.
try! await client.loginWithAccessToken(accessToken: initialAccessToken)
Handler must be registered first. Always call setAccessTokenHandler() before loginWithAccessToken(). If no handler is registered, the SDK cannot renew expired tokens and will throw an error.

Security Best Practices

Production Token Management

Auth tokens must be generated by your secure backend to establish server-to-server trust with social.plus.Refer to the general API Reference introduction until the dedicated authentication endpoint page is published.
// Example Node.js backend - generates tokens for verified users
app.post('/api/auth/social-plus-token', async (req, res) => {
  const { userId } = req.body;
  
  // STEP 1: Verify user is authenticated in YOUR system
  const user = await verifyUserInYourSystem(userId);
  if (!user) {
    return res.status(401).json({ error: 'User not authenticated in your system' });
  }
  
  // STEP 2: Generate social.plus auth token for this verified user
  const authToken = generateSocialPlusToken(userId);
  
  // STEP 3: Return token to your app for social.plus login
  res.json({ 
    authToken,
    message: 'Token generated for verified user'
  });
});
Why this approach?
  • Your backend vouches for the user’s authenticity to social.plus
  • social.plus trusts users who have valid tokens from your verified backend
  • Prevents unauthorized access to social.plus features
  • Maintains security boundary between your auth system and social.plus

Authentication Best Practices

  • Monitor session state changes in your app’s main navigation logic
  • Handle token expiration gracefully with automatic refresh
  • Provide clear feedback to users during state transitions
  • Clean up subscriptions when components unmount
  • Use secure logout when security is critical
  • Store tokens securely using platform-specific secure storage
  • Don’t ignore session state changes - they indicate important authentication events
  • Don’t store sensitive data when user is not authenticated
  • Don’t make API calls before reaching established state
  • Don't forget to handle the terminated state - users may be banned
  • Don’t expose API keys in client-side code
  • Don’t use plain text storage for auth tokens

Troubleshooting

Symptoms: Login never completes, app shows loading indefinitelySolutions:
  1. Check your API key and network connection
  2. Verify authentication token is valid
  3. Ensure you’re using the correct region
  4. Check for console errors or network timeouts
Symptoms: Users get logged out too oftenSolutions:
  1. Check your backend token expiration settings
  2. Verify session handler implementation
  3. Ensure token refresh logic works correctly
  4. Consider longer token expiration for better UX
Symptoms: Tokens don’t refresh automaticallySolutions:
  1. Verify you’re passing the session handler during login
  2. Check that your backend token has appropriate expiration
  3. Ensure session handler implementation handles errors
  4. Test with shorter token expiration for debugging
Symptoms: App crashes when authentication state changesSolutions:
  1. Ensure UI updates happen on the main thread
  2. Handle all possible session states in switch statements
  3. Add proper null checks and error handling
  4. Clean up observers when components unmount
Symptoms: Calling loginWithAccessToken() throws an error before reaching the serverSolutions:
  1. Ensure you called setAccessTokenHandler() before loginWithAccessToken() — the handler must be registered first
  2. Verify your JWT is well-formed (valid JSON Web Token structure)
  3. Check that the JWT contains the required userId claim
  4. Confirm your backend is signing the token with the key configured in the social.plus console
Symptoms: Token expires but the SDK does not invoke your onTokenRenew handlerSolutions:
  1. Verify you logged in via loginWithAccessToken() — the handler is only invoked for access-token sessions, not default login() sessions
  2. Check that the handler was registered with setAccessTokenHandler() before login
  3. Ensure the user is not globally banned — the SDK skips handler invocation for banned users

Next Steps

User Management

Learn about user profiles and management

Social Module Overview

Explore social capabilities structure

Chat Module Overview

Add real-time messaging

Console Overview

Configure security and settings in the Console