Skip to main content

Implementing OAuth and Social Login

1. Using Auth Session

Example: Setting up AuthSession

import * as AuthSession from 'expo-auth-session';
import { Redirect } from 'expo-router';

const discovery = {
  authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
  tokenEndpoint: 'https://oauth2.googleapis.com/token',
  revocationEndpoint: 'https://oauth2.googleapis.com/revoke',
};

const config = {
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  redirectUrl: AuthSession.makeRedirectUri({ useProxy: true }),
  scopes: ['openid', 'profile', 'email'],
};

export default function OAuthScreen() {
  const [request, response, promptAsync] = AuthSession.useAuthRequest(
    config,
    discovery
  );

  if (response) {
    if (response.error) {
      console.log('OAuth error:', response.error);
    } else if (response.type === 'success') {
      const { access_token } = response.params;
      // Handle the token
    }
  }

  return (
    <Redirect href={request ? request.url : '#'} />
  );
}
Property Description Values
authorizationEndpoint URL to redirect user for authorization https://accounts.google.com/o/oauth2/v2/auth
tokenEndpoint URL to exchange authorization code for token https://oauth2.googleapis.com/token
revocationEndpoint URL to revoke access token https://oauth2.googleapis.com/revoke
Note: Ensure that your redirect URL is properly configured in the OAuth provider's dashboard.
Warning: Never expose client secrets in client-side code in production. Use a backend service to handle sensitive credentials.

2. Implementing OAuth Flow

Example: Setting up Expo Auth with Google

import * as AuthSession from 'expo-auth-session';
import { Google } from 'expo-auth-session/providers/google';

const config = {
  clientId: 'your-google-client-id',
  redirectUri: AuthSession.makeRedirectUri({ useProxy: true }),
  scopes: ['profile', 'email'],
};

const { authUrl, ...rest } = await AuthSession.getAuthSessionInfoAsync({
  provider: Google,
  config,
});

// Redirect user to authUrl
console.log('Redirect to:', authUrl);
Property Description Values
clientId OAuth client ID from provider 'your-google-client-id'
redirectUri Redirect URI for auth callback AuthSession.makeRedirectUri({ useProxy: true })
scopes Permissions requested ['profile', 'email']
Note: Use useProxy: true for local development to handle redirects correctly.
Warning: Never hardcode client secrets in production apps.

OAuth Flow Steps

  • User initiates login via social provider
  • Redirects to OAuth authorization URL
  • User grants permissions
  • Provider redirects back to app with auth code
  • Exchange code for access token

3. Configuring Auth Request

Property Description Example
authUrl URL to initiate OAuth flow https://accounts.google.com/o/oauth2/v2/auth
clientId Client ID from OAuth provider 1234567890-abcde.apps.googleusercontent.com
redirectUrl Redirect URI registered with provider expohost://auth/callback
scopes Permissions requested from user ["email", "profile"]

Example: Configure Auth Request

import * as WebBrowser from 'expo-web-browser';

const config = {
  authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
  clientId: '1234567890-abcde.apps.googleusercontent.com',
  redirectUrl: 'expohost://auth/callback',
  scopes: ['email', 'profile']
};

WebBrowser.openAuthSessionAsync(config.authUrl, config.redirectUrl);

4. Using Auto Discovery

Property Description Value
autoDiscovery Enables automatic discovery of OAuth endpoints true
issuer OAuth issuer URL for auto-discovery https://accounts.google.com
authorizationEndpoint OAuth authorization endpoint URL https://accounts.google.com/o/oauth2/v2/auth
tokenEndpoint OAuth token endpoint URL https://oauth2.googleapis.com/token
userEndpoint OAuth user info endpoint URL https://www.googleapis.com/oauth2/v2/userinfo

Example: Auto Discovery Configuration

import { AuthSession } from 'expo-auth-session';

const config = {
  autoDiscovery: true,
  issuer: 'https://accounts.google.com',
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  redirectUrl: AuthSession.getRedirectUrl(),
  scopes: ['profile', 'email']
};

const discovery = await AuthSession.fetchDiscoveryAsync(config.issuer);
console.log('Discovered endpoints:', discovery);

5. Using Apple Sign In

Property Description Values
provider Identifier for the Apple provider apple
clientId App ID from Apple Developer account com.example.app
clientSecret Private key from Apple Developer account secret-key-here

Example: Configure Apple Sign In

import { AppleAuth } from &#x27;@invertase/react-native-apple-auth&#x27;;

const appleAuth = new AppleAuth({
  clientId: &#x27;com.example.app&#x27;,
  clientSecret: &#x27;secret-key-here&#x27;,
  redirectUri: &#x27;https://example.com/auth/apple&#x27;,
  scope: [&#x27;name&#x27;, &#x27;email&#x27;],
  responseType: &#x27;code&#x27;,
});

export default appleAuth;
Note: Ensure that your app is registered with Apple Developer and the Sign in with Apple capability is enabled.
Warning: The clientSecret must be securely stored and not exposed in client-side code in production.

Apple Sign In Flow Summary

  • User taps "Sign in with Apple"
  • Expo handles the OAuth flow
  • Apple returns an authorization code
  • Server exchanges code for token
  • User profile is retrieved and session created

6. Implementing Google Sign In

Example: Setting up Google Sign-In with Expo

import { Google } from 'expo-auth-session/providers/google';
import * as WebBrowser from 'expo-web-browser';

const config = {
  clientId: 'YOUR_GOOGLE_CLIENT_ID',
  scopes: ['profile', 'email'],
  redirectUrl: WebBrowser.makeRedirectUri({
    scheme: 'your-app-scheme'
  }),
  discoveryUrl: 'https://accounts.google.com/.well-known/openid-configuration'
};

const handleGoogleLogin = async () => {
  const result = await Google.logInAsync(config);
  if (result.type === 'success') {
    console.log('Google login successful', result);
  } else {
    console.log('Google login failed', result);
  }
};
Property Description Value
clientId Google OAuth client ID string
scopes Permissions requested from the user string[]
redirectUrl Redirect URI for OAuth callback string
discoveryUrl OpenID Connect discovery URL string
Note: Make sure to configure your Google OAuth client in the Google Cloud Console with the correct redirect URIs.
Warning: The redirectUrl must match exactly what is configured in the Google Cloud Console.

Google Sign-In Flow Summary

  • User taps "Sign in with Google"
  • Expo opens a web browser to Google's OAuth endpoint
  • User authenticates and grants permissions
  • Google redirects back to your app with an auth code
  • Your app exchanges the code for tokens

7. Using Facebook Login

Example: Setting up Facebook Login

import * as Facebook from 'expo-facebook';

export default function FacebookLoginButton() {
  const handleLogin = async () => {
    await Facebook.initializeAsync({
      appId: 'YOUR_FACEBOOK_APP_ID',
    });
    const { type, token } = await Facebook.logInAsync({
      permissions: ['public_profile', 'email'],
    });

    if (type === 'success') {
      // Send token to your backend for validation
      console.log('Login successful with token:', token);
    } else {
      console.log('Login failed');
    }
  };

  return (
    <TouchableOpacity onPress={handleLogin}>
      <Text>Login with Facebook</Text>
    </TouchableOpacity>
  );
}
Property Description Values
appId Facebook App ID from Facebook Developer Console string
permissions Permissions requested from the user string[]
Note: Ensure your Facebook App ID is correctly configured in app.json or app.config.js.
Warning: Facebook login requires proper setup in the Facebook Developer Console, including valid redirect URIs.

Facebook Login Setup Steps

  • Create a Facebook App in the Facebook Developer Console
  • Configure the app with valid redirect URIs (e.g., exp://127.0.0.1:8081)
  • Install expo-facebook package
  • Initialize with your Facebook App ID
  • Request appropriate permissions from the user

8. Opening Auth Browser

Example: Opening Auth Browser

import * as WebBrowser from 'expo-web-browser';

const handleAuth = async () => {
  const result = await WebBrowser.openAuthSessionAsync(
    'https://example.com/oauth/authorize',
    'https://example.com/callback'
  );
  console.log(result);
};
Property Description Notes
authUrl URL to initiate OAuth flow Must be a valid HTTPS URL
redirectUrl URL to redirect to after auth Must match registered redirect URL
options Optional configuration object See below for supported keys
Note: The redirect URL must be registered with the OAuth provider.
Warning: Ensure all URLs are properly encoded to prevent security issues.
const options = {
  presentationStyle: 'pageSheet',
  preferredBarTintColor: '#000000',
  preferredControlTintColor: '#ffffff'
};

9. Storing Auth Tokens

Example: Secure Storage with Expo SecureStore

import * as SecureStore from 'expo-secure-store';

// Store auth token
await SecureStore.setItemAsync('authToken', token);

// Retrieve auth token
const token = await SecureStore.getItemAsync('authToken');

// Delete auth token
await SecureStore.deleteItemAsync('authToken');
Method Description Notes
setItemAsync(key, value) Stores a key-value pair securely Values are encrypted and stored in secure storage
getItemAsync(key) Retrieves a value by key Returns null if key does not exist
deleteItemAsync(key) Deletes a key-value pair Removes the stored value entirely
Note: SecureStore is not available on all platforms. On web, it falls back to using localStorage, which is less secure.
Warning: Never store sensitive tokens in AsyncStorage or localStorage as they are not encrypted.

Best Practices for Token Storage

  • Use Expo SecureStore for sensitive data like auth tokens
  • Clear tokens from storage when the user logs out
  • Implement token refresh logic to handle expiration
  • Use secure storage for tokens even in development mode

10. Handling Token Refresh

Property Description Example
accessToken The current access token used for API requests "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
refreshToken Token used to obtain a new access token "rJ3kLmNpQrStUvWxYzAbCdEfGhIjKlMnOpQrStUvWxYz"
expiresAt Timestamp when the current access token expires 1698765432000

Example: Refreshing Token with Expo Auth

import { AuthSession } from 'expo-auth-session';

const refreshAccessToken = async (refreshToken) => {
  const response = await fetch('https://api.example.com/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken }),
  });

  const { accessToken, expiresAt } = await response.json();
  return { accessToken, expiresAt };
};

// Usage
const newTokenData = await refreshAccessToken(refreshToken);
Note: Implement automatic token refresh before expiration to avoid auth errors.

11. Managing Session State

Property Description Values
accessToken Token used to access protected resources string
refreshToken Token used to obtain a new access token string
expiresAt Timestamp when the access token expires number
user User profile information object

Example: Storing Session State

import * as SecureStore from 'expo-secure-store';

const saveSession = async (session) => {
  await SecureStore.setItemAsync('accessToken', session.accessToken);
  await SecureStore.setItemAsync('refreshToken', session.refreshToken);
  await SecureStore.setItemAsync('expiresAt', session.expiresAt.toString());
};

const loadSession = async () => {
  const accessToken = await SecureStore.getItemAsync('accessToken');
  const refreshToken = await SecureStore.getItemAsync('refreshToken');
  const expiresAt = await SecureStore.getItemAsync('expiresAt');

  return {
    accessToken,
    refreshToken,
    expiresAt: parseInt(expiresAt),
  };
};

Example: Refreshing Session

const refreshSession = async (refreshToken) => {
  const response = await fetch('https://api.example.com/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken }),
  });

  const newSession = await response.json();
  await saveSession(newSession);
  return newSession;
};
Note: Use expo-secure-store to securely store session tokens on device.

12. Implementing Logout Flow

Example: Logout with Expo Auth

import { AuthSession } from 'expo-auth-session';
import * as WebBrowser from 'expo-web-browser';

const handleLogout = async () => {
  try {
    // Clear auth state
    await AuthSession.clearSessionAsync();
    
    // Optionally clear local storage or tokens
    // AsyncStorage.removeItem('authToken');
    
    // Redirect to login screen
    // navigation.navigate('Login');
  } catch (error) {
    console.error('Logout error:', error);
  }
};
Method Description Notes
AuthSession.clearSessionAsync() Clears the session data for the current provider Removes cached tokens and session info
AsyncStorage.removeItem() Removes stored auth tokens Optional but recommended for security
Note: Ensure all session data is cleared to prevent token reuse.

Was this article helpful?