Authentication is required to access social.plus features. This comprehensive guide will take you from basic login to production-ready authentication patterns.
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
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.
// Production mode - API key + auth tokensconst client = Client.createClient({ apiKey: 'your-prod-api-key', region: 'sg'});// Secure login with auth token from your backendawait 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.
// Development mode - API key only (for testing)const client = Client.createClient({ apiKey: 'your-dev-api-key', region: 'sg'});// Simple login without auth token (development/testing only)await client.login({ userId: 'dev-user-123', displayName: 'Developer'});
Development mode bypasses auth token requirements for easier testing. Never use this in production as it skips your backend verification.
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}
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
Monitor session state changes to handle authentication in your app:
iOS
Android
TypesScript
Flutter
var cancellable: AnyCancellable?// Observe session state changescancellable = 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() }}
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 loginlet sessionHandler = ProductionSessionHandler()try await client.login( userId: userId, displayName: displayName, authToken: authToken, sessionHandler: sessionHandler)
class ProductionSessionHandler : SessionHandler { override fun sessionWillRenewAccessToken(renewal: AccessTokenRenewal) { // Call your backend to refresh token authRepository.refreshToken { newToken -> if (newToken != null) { renewal.renewWithAuthToken(newToken) } else { renewal.unableToRetrieveAuthToken() } } }}// Use during loginval sessionHandler = ProductionSessionHandler()AmityCoreClient.login(userId) .displayName(displayName) .authToken(authToken) .sessionHandler(sessionHandler) .build() .submit()
interface SessionHandler { sessionWillRenewAccessToken: (renewal: TokenRenewal) => void;}const createProductionSessionHandler = (): Amity.SessionHandler => ({ sessionWillRenewAccessToken: async (renewal: Amity.AccessTokenRenewal) => { try { // Request fresh token from your backend (server-to-server) // Your backend re-verifies the user and generates new token const newToken = await AuthService.refreshToken(); renewal.renewWithAuthToken(newToken); } catch (error) { console.error('Token refresh failed:', error); renewal.unableToRetrieveAuthToken(); } }});// Use when logging in with backend-verified tokenawait client.login({ userId: 'user-123', displayName: 'John Doe' authToken: 'your-auth-token', }, sessionHandler);
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.
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.
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.
iOS
Android
TypeScript
// 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)
// 1. Implement the AccessTokenHandler interface.// 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.val handler = object : AccessTokenHandler { override suspend fun onTokenRenew(userId: String): String { // get new token from your api val response = myApiService.refreshToken(userId) return response.accessToken }}// 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.AmityCoreClient.setAccessTokenHandler(handler)// 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.AmityCoreClient.loginWithAccessToken(accessToken) .build() .submit() .subscribe()
import { Client } from "@amityco/ts-sdk";// 1. Define custom token handler.// 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.const tokenHandler = { async onTokenRenew(userId: string): Promise<string> { // Request new JWT from your authentication backend const response = await fetch("https://your-backend.com/api/refresh-token", { method: "POST", credentials: "include", userId, }); const data = await response.json(); return data.accessToken; },};// 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.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.await Client.loginWithAccessToken(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.
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 usersapp.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