Social login in React Router v7: Google, GitHub, and Microsoft
A complete guide to social login in React Router v7, covering Google, GitHub, Microsoft, and every provider you will need as you grow.
React Router v7 framework mode changed what authentication looks like in a React application. Loaders run on the server. Actions handle mutations. Sessions live in encrypted cookies. Social login fits into this model cleanly once you understand where each part of the OAuth flow belongs.
The short answer: the authorization redirect goes out from a loader, the callback code exchange happens in another loader, and the session is set server-side before the user ever sees your app. No client-side token juggling, no localStorage, no hydration mismatches. The browser never touches your OAuth client secret or your access tokens.
This guide covers how social login works in React Router v7, how to implement it from scratch to understand the moving parts, and how WorkOS AuthKit lets you configure Google, GitHub, Microsoft, and more without writing any OAuth plumbing yourself.
How social login maps onto React Router v7
OAuth 2.0 has five steps. Here is where each one lives in React Router v7 framework mode:
- Generate the authorization URL. A loader on your sign-in route generates the provider's authorization URL, stores a CSRF state value in a short-lived cookie, and returns a redirect response. This is a loader, not an action, because the user navigates to
/loginwith a GET request. - Redirect to the provider. The browser follows the redirect to Google, GitHub, or Microsoft. The user authenticates there.
- Provider redirects to your callback. The provider appends
?code=xxx&state=yyyto your registered callback URL and redirects the browser back. - Exchange the code for tokens. A loader on your callback route validates the state, exchanges the code for an access token, and fetches the user's profile. This must happen server-side because it requires your client secret.
- Set the session and redirect. The callback loader creates or updates the user in your database, writes a session cookie, and redirects to your app.
The session cookie is httpOnly, server-set, and signed. The client never sees the OAuth tokens. This is what makes server-side auth more robust than the client-side pattern most React developers learned from single-page app tutorials.
The OAuth security details that React Router makes visible
- State validation. The authorization URL must include a random
stateparameter stored in a cookie. Your callback loader checks that thestatein the query string matches the cookie before exchanging the code. Without this check, an attacker can craft a URL that logs your user into the attacker's account. Every provider requires state validation, and every OAuth implementation gets it wrong at least once. - Loaders, not useEffect. Client-side auth tutorials use
useEffectto detect the OAuth callback and exchange the code in the browser. This exposes your client secret if you put it in client-side code, or requires a separate API route if you keep it server-side. In React Router v7 framework mode, the callback is a loader. It runs on the server. There is no client-side workaround needed. - Actions handle sign-out, not sign-in. Sign-in starts with a GET request to your login route. Sign-out is a mutation that clears the session, so it belongs in an action triggered by a form POST. This is the idiomatic React Router pattern: read operations are loaders, write operations are actions. Mixing them up causes subtle bugs where the session is cleared but the page does not redirect correctly.
- Redirect URI registration. Register your exact callback URL in each provider's developer console. Providers reject mismatched redirect URIs, which shows up as confusing error messages. A trailing slash difference between your registered URI and the one in your code will break the flow silently until you look at the provider's error response.
Building OAuth from scratch: Google as an example
Here is the full implementation for Google. Reading through it once gives you the mental model that makes the WorkOS approach more understandable.
The sign-in route
The callback route
The sign-out action
Sign-out uses a form POST, not a link. A GET request to a sign-out URL can be triggered by a third party (via an image tag or prefetch) and log the user out without their intent. The form POST with an action is the correct approach.
Adding GitHub
GitHub's implementation follows the same pattern with a few provider-specific differences worth knowing:
The private email fallback catches a lot of developers by surprise. Skip the /user/emails call and users who have set their GitHub email to private will have a null email address in your database, which breaks email verification, transactional emails, and any feature that assumes email is present.
Adding Microsoft
Microsoft uses a tenant-specific authorization endpoint. For consumer accounts (personal Microsoft accounts), use common as the tenant. For enterprise accounts tied to a specific Azure AD tenant, you replace common with the tenant ID - which is where Microsoft's OAuth implementation becomes relevant for B2B use cases.
At this point you have three providers, three authorization URLs, three token endpoints, three profile shapes, and a growing list of provider-specific edge cases. If you add Apple (JWT assertions instead of a standard token response), LinkedIn (different profile field names), or GitLab (self-hosted instance support), the surface area compounds quickly.
This is the practical motivation for using a library: not that the individual implementation is hard, but that doing it correctly and maintaining it across providers is ongoing work that does not differentiate your product.
Using WorkOS AuthKit for social login
WorkOS AuthKit handles the full OAuth implementation for every supported provider. You configure which providers to enable in the WorkOS dashboard, and AuthKit routes users through the appropriate flow automatically. Your React Router application never touches provider-specific endpoints.
The full list of providers with integration guides is: Google, Microsoft, GitHub, Apple, GitLab, LinkedIn, Slack, and Xero. When WorkOS adds a new provider, you enable it in the dashboard. No code changes, no redeployment.
Option 1: the AI installer
The fastest path is the WorkOS CLI. One command, and it detects your React Router setup, installs the correct SDK, configures your WorkOS dashboard, creates the callback and sign-in routes, sets up environment variables, and validates the build:
Here is what it looks like running against a React Router v7 project:
From there, enabling Google or GitHub is a toggle in the WorkOS dashboard under Authentication. No code changes required.
You can also install per-framework if auto-detection does not pick up your setup:
Option 2: manual setup
If you prefer to set things up yourself or want to understand what the installer creates, the manual path:
Then create the three routes the installer would have written:
The callback route
authLoader handles the CSRF state check, the code exchange, token validation, and session creation. The onSuccess callback is where you sync to your database and optionally persist the provider's OAuth token if you requested custom scopes.
One important note on upsert key: always use the WorkOS user ID (user.id), not the email address. If a user authenticates via Google, then later via GitHub with the same email, WorkOS links those to the same user through identity linking. Keying on WorkOS user ID means your database record stays correct without duplicates.
The sign-in route
A critical detail here: getSignInUrl (as of SDK v0.10.0) returns an object with url and headers, not a bare string. The headers contain a short-lived cookie used for PKCE and CSRF protection. If you forward only the URL and drop the headers, the callback will fail its state validation. Always pass the entire redirect response including headers.
This route also serves as the sign-in endpoint (also known as initiate_login_uri) in the WorkOS dashboard. Set the sign-in endpoint under Redirects to this route's URL. This is required for impersonation and for WorkOS-initiated flows to work correctly.
The sign-out route
Protecting routes
For routes that require authentication, use authkitLoader. It checks the session, refreshes the token if needed, and returns the authenticated user or redirects to your sign-in route:
For routes where you want to show different content for signed-in and signed-out users (a homepage, for example), omit ensureSignedIn and handle the null user case:
For advanced cases where you need direct access to the session data (including role, permissions, and accessToken) without the automatic redirect behavior, use withAuth:
Configuring providers in the WorkOS dashboard
Each provider requires an OAuth app created at the provider's developer console, with the client ID and secret pasted into the WorkOS dashboard. WorkOS then handles the OAuth flow on the provider's behalf.
- Google. Create credentials at console.cloud.google.com under APIs and Services. Create an OAuth 2.0 client ID with application type "Web application." Set the authorized redirect URI to
https://auth.workos.com/sso/oauth/google/callback. Add the client ID and secret in the WorkOS dashboard under Authentication, then Google OAuth. - GitHub. Create an OAuth App at github.com/settings/developers. Set the authorization callback URL to
https://auth.workos.com/sso/oauth/github/callback. Add the client ID and secret to WorkOS under GitHub OAuth. - Microsoft. Register an app at portal.azure.com under Azure Active Directory, App registrations. Add
https://auth.workos.com/sso/oauth/microsoft/callbackas a redirect URI under Authentication. Create a client secret under Certificates and secrets. Add both to WorkOS under Microsoft OAuth.
The WorkOS dashboard has step-by-step guides linked from each provider's configuration page. Once configured and enabled, the provider button appears automatically on the AuthKit sign-in page. Disabling a provider removes the button without any code change.
Which providers to enable
- Google is the default first choice. It covers both personal Gmail accounts and Google Workspace accounts used by most small and medium businesses. The highest-converting social login for most web applications.
- GitHub is the right second choice for developer tools, APIs, CLIs, and any product targeting technical users. Developers are already authenticated with GitHub everywhere. For a SaaS aimed at engineering teams, GitHub often matches or beats Google on conversion.
- Microsoft becomes important as you move upmarket. Many enterprise organizations standardize on Microsoft 365 and Entra ID. Microsoft social login covers personal Microsoft accounts. When enterprise customers need their entire organization to authenticate through their corporate identity provider with centralized access control, that transitions from social login to enterprise SSO, which WorkOS also handles with the same SDK.
- Apple is required by App Store guidelines if your iOS app offers any third-party social login. Worth enabling for web applications with a mobile counterpart, or consumer-facing products where Sign in with Apple has traction.
- GitLab suits open-source platforms and developer tools with a strong GitLab user base. LinkedIn suits professional networks and B2B tools where professional identity is relevant. Slack suits tools that integrate into workplace workflows. Xero suits accounting and finance tools. Enable these when your product context makes them a natural fit.
Account linking and the onSuccess upsert
When a user who created an account with email and password tries to sign in with Google using the same address, WorkOS handles this through identity linking by default. The social login is linked to the existing account rather than creating a duplicate. The user is signed in as the same user regardless of how they authenticated.
This matters for how you write your onSuccess upsert. Always key on the WorkOS user ID, not the email:
WorkOS keeps the user's email in sync with their social provider. If the user changes their email at Google, the WorkOS user record updates on their next login, and your update block propagates the change to your database automatically.
Custom OAuth scopes
WorkOS supports custom OAuth scopes for Google, Microsoft, GitHub, GitLab, and Xero. This lets you request additional permissions on top of the default profile and email access, without building a separate OAuth flow.
Common uses: read a user's Google Calendar, access their Microsoft mailbox, list their GitHub repositories, or read their GitLab projects. Configure additional scopes in the WorkOS dashboard per provider. The scopes are requested during the authorization flow, and the provider's access token is available in oauthTokens.accessToken inside your onSuccess callback.
When social login is not enough
Social login handles consumer and developer-facing authentication well. It covers personal accounts and Google Workspace or Microsoft 365 accounts at smaller companies. It does not cover what enterprise customers actually require: signing in through their company's identity provider, with access controlled centrally by IT and revoked automatically when employees leave.
That is enterprise SSO. Okta, Azure AD, Ping Identity, OneLogin, and others, accessed via SAML or OIDC. Enterprise customers do not authenticate with their personal Google or GitHub accounts. They authenticate through a corporate identity provider that enforces device policies, MFA requirements, and immediate deprovisioning.
WorkOS SSO handles enterprise login using the same session model as social login. From your application's perspective, a user authenticated via Google and a user authenticated via their company's Okta instance look identical. The user object from authkitLoader or withAuth has the same shape either way.
The path for a B2B product is: enable social login now for easy self-serve onboarding, then add enterprise SSO as the feature that unlocks deals with customers whose IT departments require it. Both live in the same WorkOS dashboard. No architectural changes to your React Router application when you add SSO later.
Production checklist
- Register your callback URL exactly at each provider's developer console, including the protocol, domain, and path. A mismatch shows up as a redirect URI error from the provider.
- Set the sign-in endpoint in the WorkOS dashboard under Redirects to your
/loginroute URL. This is required for impersonation and WorkOS-initiated flows. - Forward the full
{ url, headers }response fromgetSignInUrlon the redirect. The headers carry the PKCE/CSRF cookie. Dropping them causes callback failures. - In your
onSuccesshook, upsert onuser.id(the WorkOS ID), not on email. - Treat
WORKOS_API_KEY,WORKOS_CLIENT_ID, andWORKOS_COOKIE_PASSWORDas secrets. Never commit them. RotatingWORKOS_COOKIE_PASSWORDinvalidates all existing sessions. - Test the "new user" path (first login creates a database record) and the "returning user" path (subsequent logins update it) separately.
- Enable providers in the WorkOS dashboard before testing. A provider that is configured but not enabled does not appear on the sign-in page.
- Run
workos doctorfrom the CLI to diagnose integration issues in your local environment.
Conclusion
Social login in React Router v7 framework mode is cleaner than most frameworks because the full OAuth flow lives server-side. Loaders handle the authorization redirect and the code exchange. The session cookie is set before the browser ever touches your app. No client-side token juggling.
The manual implementation for one provider takes an hour and teaches you the security model well. The manual implementation for four providers with edge cases handled correctly takes longer and does not make your product better.
The WorkOS CLI installs everything in two minutes. After that, adding a provider is a dashboard toggle. When enterprise customers ask for SSO, the same SDK handles it without any architectural changes to how your loaders and actions work.
Sign up for WorkOS and add social login to your React Router application.