← Back to documentation

Social login setup (Google & Apple)

A step-by-step guide for project owners to let their app's end-users sign in with Google or Apple. This is white-label: you use your own OAuth credentials, so the consent screen shows your app — not manggaleh.

For an assistant guiding a customer: this page is self-contained. Before starting, ask the customer for: (1) their project slug, (2) which environment they're configuring (dev / staging / prod), and (3) their app's public URL (e.g. https://app.acme.com). Do each provider's steps in order; every value the customer needs to copy has an exact source named below. The callback URL is the #1 source of mistakes — always copy it from the dashboard, never type it by hand.


How it works (30-second mental model)

user clicks "Sign in with Google" in your app
  → your app calls client.auth.signInSocial({ provider, callbackURL })
  → manggaleh returns Google's authorization URL; your app redirects the browser there
  → user approves on Google
  → Google redirects back to MANGGALEH's callback URL (with a one-time code)
  → manggaleh exchanges the code (using YOUR client secret), creates/links the end-user
    in your environment, starts a session, and redirects the browser to your callbackURL
  → your app calls client.auth.getSession() → the user is signed in

The registered "redirect URI" at Google/Apple is manggaleh's callback URL, not your app's. Your callbackURL is only where manggaleh sends the browser after login completes.

Where the dashboard settings live: open your project → pick the environment → Sign-up tab. You'll use two sections there: Auth origins and Social login.


Part A — Google

A1. Create OAuth credentials in Google Cloud Console

  1. Go to https://console.cloud.google.com/ → create or pick a project.
  2. APIs & Services → OAuth consent screen: choose External, set your app name and logo (this is what users see on the consent screen), and add your support email. Publish it (or add test users while in "Testing").
  3. APIs & Services → Credentials → Create Credentials → OAuth client ID.
  4. Application type: Web application. Give it a name (e.g. "Acme — prod").
  5. Under Authorized redirect URIs, click Add URI and paste the exact callback URL shown in manggaleh (see A2). It looks like:
    https://<your-manggaleh-api-host>/api/t/<slug>/<env>/auth/callback/google
    
  6. Create. Copy the Client ID and Client secret.

A2. Enter it in manggaleh

  1. Dashboard → project → environment → Sign-up tab → Social login.
  2. First, copy the "Callback URL" shown under Google there and register it in Google (step A5 above) — the dashboard is the source of truth for this URL.
  3. Tick Google, paste Client ID and Client secret, and Save. (The secret is stored encrypted and never shown again — leave the field blank on future edits to keep it.)

A3. Allow your app to receive the return

In the same Sign-up tab → Auth origins, add your app's origin, e.g. https://app.acme.com. This lets manggaleh accept your callbackURL after login. (A relative callbackURL like /auth/done also works without this.)

Field map (Google):

Google Console manggaleh field
Client ID Client ID
Client secret Client secret
Authorized redirect URI Callback URL (copy from manggaleh into Google)

Part B — Apple

Apple needs an Apple Developer Program membership ($99/yr) and four identifiers. It's more involved than Google — take the steps in order.

B1. Gather the four Apple values

At https://developer.apple.com/account/Certificates, Identifiers & Profiles:

  1. App ID — under Identifiers, create (or reuse) an App ID with the Sign in with Apple capability enabled.
  2. Services ID — create an Identifier of type Services ID (e.g. com.acme.web). This string is your client_id. Enable Sign in with Apple on it, then Configure:
    • Primary App ID: the App ID from step 1.
    • Domains and Subdomains: your manggaleh API host (e.g. api.manggaleh.com).
    • Return URLs: paste the Apple callback URL shown in manggaleh:
      https://<your-manggaleh-api-host>/api/t/<slug>/<env>/auth/callback/apple
      
  3. Key (.p8) — under Keys, create a key with Sign in with Apple enabled. Download the .p8 file (you can only download it once!) and note the Key ID.
  4. Team ID — shown at the top-right of the developer portal (a 10-character string).

B2. Enter it in manggaleh

Dashboard → Sign-up tab → Social login → tick Apple and fill:

Apple value manggaleh field
Services ID (e.g. com.acme.web) Services ID
Team ID (10 chars) Team ID
Key ID (from the key) Key ID
Contents of the .p8 file Private key (.p8)
Return URL Callback URL (copy from manggaleh into Apple)

Then Save. manggaleh generates the client-secret JWT Apple requires from your .p8 + Team/Key/Services IDs automatically — you don't create it yourself.

Also add your app origin under Auth origins (same as Google, step A3).

B3. Apple gotchas (tell the customer up front)


Part C — In your app (the SDK)

import { createClient } from "@manggaleh/sdk";

const client = createClient({ tenant: "acme", env: "prod", apiKey: "mgpk_…" });

// On your "Sign in with Google" (or Apple) button:
async function signInWithGoogle() {
  const { url } = await client.auth.signInSocial({
    provider: "google",                          // or "apple"
    callbackURL: "https://app.acme.com/auth/done", // must be a trusted origin, or a relative path
  });
  window.location.href = url!;                    // browser goes to Google, then back to callbackURL
}

// On your /auth/done page (after the redirect back):
const session = await client.auth.getSession();   // → the signed-in end-user, or null

After this the user is a normal end-user in that environment — subject to RLS, ABAC permissions, everything. You can link, list, or manage them like any other user.

The snippet above works when your app is served from the manggaleh API origin (the session cookie is first-party). If your app is on a different origin — a separate domain, or a Capacitor app (capacitor://localhost / http://localhost) — use the token bridge below.


Capacitor / cross-origin web apps

A Capacitor app is a web app in a native WebView, and its origin is cross-origin to the API, so the plain cookie flow can't hand the session back. Use returnTo + completeSocialSignIn(): manggaleh routes the OAuth return through a token bridge and sends you back with the session token in the URL fragment. This works the same regardless of how Capacitor serves your app — you just register the right origin and set returnTo to it. Two common modes:

1. Register your app's origin under Sign-up → Auth origins (dashboard) — whichever your Capacitor config actually uses:

capacitor://localhost      # iOS bundled (Capacitor default)
http://localhost           # Android bundled (default) — or your server.hostname
https://app.acme.com       # remote server.url mode

2. Start sign-in with returnTo (the URL to land on after login):

const { url } = await client.auth.signInSocial({
  provider: "google",                          // or "apple"
  returnTo: "capacitor://localhost/auth/done", // bundled; or "https://app.acme.com/auth/done"
});                                             // (server.url mode). Must match an Auth origin.
window.location.href = url!;                   // WebView → Google → bridge → back to returnTo

3. Finish on your return page (/auth/done):

const session = await client.auth.completeSocialSignIn(); // reads #token from the URL, stores it
// session.user is now signed in; the SDK uses the token as its bearer for all calls

That's it — no cookies, works in the WebView. Notes:


Per-environment: important

Each environment (dev, staging, prod) has its own callback URL and its own OAuth config:

https://…/api/t/acme/dev/auth/callback/google
https://…/api/t/acme/prod/auth/callback/google   ← different!

So you either register multiple redirect URIs on one Google OAuth client (one per env), or create a separate OAuth client per environment. The dashboard always shows the correct callback URL for the environment you're viewing — copy that one.


Troubleshooting

Symptom Cause Fix
Invalid callbackURL / INVALID_CALLBACK_URL from manggaleh Your callbackURL isn't a trusted origin Add your app origin under Sign-up → Auth origins, or use a relative path (/auth/done)
Capacitor: Invalid or untrusted return URL on the bridge (400) Your returnTo origin isn't registered Add the exact Capacitor origin (capacitor://localhost, http://localhost, …) under Sign-up → Auth origins
Capacitor: back on the app but completeSocialSignIn() returns null The return page didn't receive the #token fragment Ensure returnTo points at a page that runs the SDK and calls completeSocialSignIn(); check the URL kept its #… fragment
Google: redirect_uri_mismatch The redirect URI registered in Google ≠ the callback manggaleh sends Copy the exact callback URL from the dashboard into Google's Authorized redirect URIs (watch for a missing /, wrong env, or http vs https)
Google: consent screen blocked / "app not verified" OAuth consent screen still in Testing Add the tester's email as a test user, or publish the consent screen
Apple: invalid_client Wrong Services ID / Team ID / Key ID, or the .p8 doesn't match the Key ID, or the Return URL isn't registered on the Services ID Re-check all four values in Social login, and confirm the Return URL is listed on the Services ID's Sign in with Apple config
Apple: invalid_grant / redirect fails Return URL is http/localhost, or domain not verified Use an HTTPS domain; add it under Domains and register the exact Return URL
Signed in but getSession() is null on your page callbackURL pointed somewhere that didn't load the SDK/cookie Ensure the return page runs the SDK on the same origin you configured
Provider button does nothing / 404 on /sign-in/social Provider not enabled/saved in manggaleh Tick the provider and Save in Social login; confirm the Client ID/secret (or Apple values) are filled

Checklist (quick reference)

Google

Apple

App