AnswerixAI Docs AnswerixAI Docs AI Search Visibility, GEO & AEO platform

OAuth social login setup

Configure optional Google / GitHub sign-in via Laravel Socialite.

On this page 8

Google / GitHub Social Login — Operational Setup Guide

The "Continue with Google" / "Continue with GitHub" buttons on the sign-in page (resources/js/components/auth/oauth-buttons.tsx) are backed by a real Socialite-based implementation (app/Http/Controllers/Auth/OAuthController.php). The buttons themselves are always visible (there's no frontend check for whether credentials are configured) — but until the env vars below are set, clicking one redirects back to /login with a friendly "Google/GitHub sign-in is not configured on this server" error instead of reaching the provider. Nothing crashes either way; nobody can actually sign in with them until you set these up.

Credentials you'll end up with

Env variable What it is Where it comes from
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET OAuth2 app identity for Google sign-in Google Cloud Console → Credentials
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET OAuth2 app identity for GitHub sign-in GitHub → Developer settings → OAuth Apps

Both are read by config/services.php and consumed by Laravel\Socialite\Facades\Socialite in OAuthController. No refresh tokens or offline access are needed here — this is a standard "sign in with X" login flow, not a data-access integration like Google Ads.

Redirect URIs — get these exactly right

Socialite builds the callback URL from config('services.{provider}.redirect'), which is a relative path resolved against APP_URL:

Provider Redirect path (already set in config/services.php) Full URI to register
Google /auth/callback/google {APP_URL}/auth/callback/google
GitHub /auth/callback/github {APP_URL}/auth/callback/github

Register one redirect URI per environment you use (local, staging, production) — e.g. for local dev with APP_URL=http://localhost:8000: http://localhost:8000/auth/callback/google. Mismatched redirect URIs are the single most common cause of OAuth failures (redirect_uri_mismatch).


Google — create an OAuth client

  1. Go to https://console.cloud.google.com/ → select or create a project (you can reuse the same project as docs/google-ads-api-setup.md if one already exists, or create a dedicated one, e.g. answerix-auth).
  2. APIs & Services → OAuth consent screen:
    • User type: External → Create.
    • Fill in the app name (e.g. "AnswerixAI"), support email, and developer contact email.
    • Scopes: no extra scopes needed — Socialite requests openid email profile by default, which needs no verification.
    • Add your own Google account as a test user while the app is in Testing status (needed to sign in yourself before publishing).
  3. APIs & Services → Credentials → Create Credentials → OAuth client ID:
    • Application type: Web application.
    • Name: e.g. "AnswerixAI Web Login".
    • Authorized redirect URIs: add the full callback URL(s) from the table above, one per environment (e.g. both the localhost:8000 and production URLs, as separate entries — Google allows multiple).
    • Click Create → copy the Client ID and Client Secret.
  4. When you're ready for real users (not just yourself as a test user), go back to OAuth consent screen → Publish App. For the basic openid/email/profile scopes this app uses, Google does not require the lengthy verification review — publishing is immediate.

GitHub — create an OAuth App

  1. Go to https://github.com/settings/developers (or, for an organization-owned app, https://github.com/organizations/{org}/settings/applications) → OAuth Apps → New OAuth App.
  2. Fill in:
    • Application name: e.g. "AnswerixAI".
    • Homepage URL: your APP_URL (e.g. https://app.answerixai.com).
    • Authorization callback URL: the full GitHub callback URL from the table above (e.g. https://app.answerixai.com/auth/callback/github). GitHub only allows one callback URL per OAuth App — if you need both a local-dev and a production callback, create two separate OAuth Apps (e.g. "AnswerixAI (dev)" and "AnswerixAI (prod)") with their own client ID/secret pairs, and use the dev one's credentials in your local .env.
  3. Click Register application.
  4. Copy the Client ID. Click Generate a new client secret and copy it immediately — GitHub only shows it once.

Configure and verify

Fill the block in .env (already present, commented out, at the bottom of .env.example):

dotenv
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GOOGLE_CLIENT_ID=xxxxxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxx

No php artisan config:cache clear is needed in local dev; in production, run php artisan config:clear && php artisan config:cache after changing .env as usual.

Verify end-to-end:

  1. Visit /login — the Google/GitHub buttons are already visible (they always render; there's no config check on the frontend).
  2. Click a button → you should now land on the real Google/GitHub consent screen, instead of bouncing back to /login with a "not configured" error.
  3. Approve → you should land back on /dashboard, signed in. Check php artisan tinker --execute 'dd(App\Models\User::latest()->first());' to confirm a user row was created with email_verified_at set and the avatar_url populated from the provider.
  4. Sign out and click the same button again with the same account — you should log into the same user row (matched by email), not create a duplicate.

How account matching works

OAuthController::callback() looks up an existing User by case-insensitive email match before creating a new one. This means:

  • If someone already has a password-based account with [email protected] and later signs in with "Continue with Google" using the same Google account's email, they land in the same account — no duplicate, no password required for that login.
  • Brand-new email addresses get a new User row with a random 40-character password (nobody knows it — the account is only reachable via OAuth or a password reset) and email_verified_at set immediately, since the OAuth provider already verified that address.

Troubleshooting

Symptom Cause / fix
Clicking a button redirects straight back to /login with "sign-in is not configured on this server" GOOGLE_CLIENT_ID / GITHUB_CLIENT_ID is empty in the running environment — check .env and that config cache was cleared after editing it. Note the buttons themselves are always visible regardless of configuration, so this is the actual signal that credentials are missing.
redirect_uri_mismatch (Google) or The redirect_uri MUST match the registered callback URL (GitHub) The registered redirect URI doesn't exactly match {APP_URL}/auth/callback/{provider} — check for http vs https, trailing slash, or wrong port.
Redirects back to /login with a generic sign-in error after approving on the provider Something threw inside Socialite::driver($provider)->user() — check storage/logs/laravel.log; common causes are a wrong/rotated client secret, or the OAuth consent screen being in Testing mode with your account not added as a test user (Google only).
"Your Google/GitHub account has no email address" The provider account has no public/verified email associated (rare for Google; GitHub accounts can hide their email). GitHub scope requested is user:email via Socialite's default, which should surface the primary email even if hidden from the public profile — if this still fails, the account likely has no verified email at all on GitHub's side.
New account created every time instead of reusing an existing one Email casing or a leading/trailing space mismatch — the app does an exact lower(email) comparison; if the provider ever returns a differently-formatted address for the same person, it won't match. Not expected in normal use.

Operational notes

  • No refresh tokens, no offline scope — this is login-only. There's nothing to rotate or re-consent beyond the client ID/secret themselves.
  • Rotating a client secret: generate a new one in Google Cloud Console / GitHub OAuth App settings, update the env var, redeploy. The old secret stops working immediately — do this during a low-traffic window if you're worried about in-flight logins (the window is typically seconds).
  • Multiple environments: use separate OAuth apps/clients per environment (dev/staging/prod) rather than reusing one with multiple redirect URIs — GitHub in particular only supports one callback URL per app, and keeping environments on separate credentials makes it easy to revoke a compromised dev credential without touching production.
  • Whitelabel deployments: the current implementation reads one global GOOGLE_CLIENT_ID/GITHUB_CLIENT_ID pair from config/services.php — it is not per-whitelabel like Stripe. All whitelabel domains share the same OAuth app, so the redirect URI registered with Google/GitHub must cover whichever domain(s) actually serve /auth/callback/*. If a specific whitelabel agency needs their own OAuth branding (their app name shown on the Google consent screen instead of "AnswerixAI"), that would require extending OAuthController/config/services.php to resolve per-whitelabel credentials the same way Stripe does — out of scope for the current setup.