EasyStarter logoEasyStarter
Authentication

Social Login

Configure Google OAuth and Apple native social login

Social Login

EasyStarter's mobile app includes the following social login providers:

  • Google OAuth
  • Apple native sign-in (iOS only)

Server configuration lives in apps/server/src/lib/auth.ts. Apple Sign-In uses the native ID token flow: the app triggers the system-level Apple sign-in sheet, retrieves the identityToken, and passes it directly to Better Auth for verification — no web redirect needed.

Required Environment Variables

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
APPLE_APP_BUNDLE_IDENTIFIER=

Create Google OAuth Client

Google Cloud Console: Google Cloud Console

  1. Log in and select or create a project
  2. Go to APIs & Services > Credentials
  3. Click Create Credentials → select OAuth client ID
  4. Complete the OAuth consent screen if prompted
  5. Select Web application as the application type
  6. Configure the redirect URI

Key fields:

  • Authorized JavaScript origins: your frontend URL, e.g. https://yourdomain.com
  • Authorized redirect URIs: {SERVER_URL}/api/auth/callback/google

Mobile Google OAuth requires an HTTPS callback URL. Use ngrok to expose your local server over HTTPS.

Why ngrok is required for mobile development

Mobile Google Sign-In uses a deep link callback flow, not a simple browser redirect:

  1. The app opens Google's login page via expo-web-browser
  2. After the user logs in, Google redirects to the server callback URL (SERVER_URL/api/auth/callback/google)
  3. The server processes the callback, then redirects the user back to the app via a deep link (e.g. myapp://callback)
  4. The OS intercepts the deep link, relaunches the app, and the login completes

This flow has two hard requirements:

  • Google OAuth enforces HTTPShttp://localhost is not accepted
  • Physical devices and simulators cannot access your dev machine's localhost directly — the server must have a publicly reachable address

Ensure Deep Link Scheme Consistency

In step 3 above, the server redirects the user back to the app via a deep link (e.g. myapp://callback). The scheme must match in two places:

  • nativeScheme in packages/app-config/src/app-config.ts
packages/app-config/src/app-config.ts
nativeScheme: "myapp"
  • scheme in apps/native/app.json
apps/native/app.json
{
  "expo": {
    "scheme": "myapp"
  }
}

These two values must be identical, otherwise the OS cannot relaunch the app after the Google OAuth callback.

ngrok solves both: it exposes your local localhost:3001 as a public HTTPS URL, so Google can complete the redirect and the server can send the user back to the app via deep link.

Install ngrok

Download and install from the ngrok website, or use Homebrew:

brew install ngrok

After installing, sign up for a free account and authenticate:

ngrok config add-authtoken YOUR_AUTH_TOKEN

Find your Auth Token at ngrok Dashboard → Your Authtoken.

Start the tunnel

After starting the local server (pnpm dev:server), open a new terminal and run:

ngrok http 3001

ngrok will output an HTTPS URL like:

Forwarding  https://xxxx-xxxx.ngrok-free.app -> http://localhost:3001

Use this URL as the Google OAuth redirect URI:

https://xxxx-xxxx.ngrok-free.app/api/auth/callback/google

Also update SERVER_URL in .dev.vars to this ngrok URL so Better Auth's baseURL and the OAuth callback stay in sync.

Note: The free ngrok plan generates a new URL on every restart. You'll need to update both the Google Cloud Console redirect URI and your local .dev.vars each time.

After creating, you'll receive:

  • Client IDGOOGLE_CLIENT_ID
  • Client SecretGOOGLE_CLIENT_SECRET

Configure Apple Native Sign-In

The mobile Apple Sign-In uses the native iOS flow: the app calls expo-apple-authentication to trigger the system sign-in sheet, retrieves the Identity Token, and the server validates it using the Bundle ID (APPLE_APP_BUNDLE_IDENTIFIER) as the audience.

Reference: Better Auth Apple docs

Enable Sign In with Apple on your App ID

The App ID was already created in the Configure app.json chapter. Now enable Apple Sign-In on it:

  1. Log in to Apple Developer Portal → Identifiers
  2. Find and click your App ID
  3. Under Capabilities, check Sign In with Apple
  4. Click Continue → Save

Create and configure a Service ID

  1. In Identifiers, click +, select Service IDs → Continue
  2. Enter a Description and Identifier (e.g. com.yourcompany.yourapp.si) — this becomes your APPLE_CLIENT_ID
  3. Click Register
  4. Click the Service ID you just created → check Sign In with Apple → click Configure
  5. Under Primary App ID, select your App ID
  6. Configure Domains and Subdomains and Return URLs:
EnvironmentDomains and SubdomainsReturn URLs
Developmentxxxx-xxxx.ngrok-free.apphttps://xxxx-xxxx.ngrok-free.app/api/auth/callback/apple
Productionserver.yourdomain.comhttps://server.yourdomain.com/api/auth/callback/apple

In development, use your ngrok URL. Remember to update both the Domain and Return URL here every time ngrok restarts. In production, use your actual server domain.

  1. Click Next → Done → Continue → Save

Set Environment Variables

For local development, add everything to apps/server/.dev.vars:

apps/server/.dev.vars
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
APPLE_APP_BUNDLE_IDENTIFIER=com.yourcompany.yourapp

For production, put sensitive values in apps/server/.env.production:

apps/server/.env.production
GOOGLE_CLIENT_SECRET=your-google-client-secret

Add non-sensitive IDs to vars in apps/server/wrangler.jsonc:

apps/server/wrangler.jsonc
"vars": {
  "GOOGLE_CLIENT_ID": "your-google-client-id",
  "APPLE_APP_BUNDLE_IDENTIFIER": "com.yourcompany.yourapp"
}

Supported Social Login Providers

  • Google OAuth (via deep link callback)
  • Apple native sign-in (via ID token, iOS only)

Apple Sign-In is only available on physical devices and TestFlight. It does not work in the iOS Simulator.