OAuth Setup#
AuthHero supports Google GitHub Facebook OAuth providers out of the box. Each follows the same architecture: a Strategy Pattern with a common interface, so adding new providers is trivial.
How OAuth Works in AuthHero#
AuthHero implements a secure OAuth flow with these key properties:
- CSRF protection — Random state parameter stored in an httpOnly cookie and validated on callback
- No tokens in URLs — Session tokens are stored in Redis behind a one-time code; only the opaque code appears in the redirect URL
- Automatic account linking — If a user with the same email already exists, the OAuth account is linked (in a transaction)
- MFA-compatible — If the OAuth user has MFA enabled, they're redirected through the MFA challenge before getting tokens
Google OAuth Setup#
Create a Google Cloud project
Go to console.cloud.google.com and create a new project (or use an existing one).
Enable the Google+ API
Navigate to APIs & Services → Library and enable the Google+ API (or the Google People API).
Configure the OAuth consent screen
Go to APIs & Services → OAuth consent screen. Set the user type to External. Fill in the app name and support email. Add the scopes: openid, email, profile.
Create OAuth credentials
Go to APIs & Services → Credentials → Create Credentials → OAuth client ID. Select Web application.
Add the authorized redirect URI:
http://localhost:5000/auth/oauth/callback/googleCopy credentials to .env
Copy the Client ID and Client Secret:
GOOGLE_CLIENT_ID=123456789-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx
GOOGLE_REDIRECT_URI=http://localhost:5000/auth/oauth/callback/googleGitHub OAuth Setup#
Create a GitHub OAuth App
Go to github.com/settings/developers → OAuth Apps → New OAuth App.
Fill in the app details
Set the Homepage URL to your app URL and the Authorization callback URL to:
http://localhost:5000/auth/oauth/callback/githubGenerate a client secret
After creating the app, click Generate a new client secret.
Copy credentials to .env
GITHUB_CLIENT_ID=Ov23li...
GITHUB_CLIENT_SECRET=abc123...
GITHUB_REDIRECT_URI=http://localhost:5000/auth/oauth/callback/githubAuthHero requests the user:email scope and makes a separate API call to /user/emails because GitHub doesn't always include the email in the profile response (it can be private). AuthHero picks the primary verified email.
Facebook OAuth Setup#
Create a Facebook App
Go to developers.facebook.com/apps → Create App → select Consumer type.
Add Facebook Login product
In the app dashboard, click Add Product and select Facebook Login. Set the Valid OAuth Redirect URIs:
http://localhost:5000/auth/oauth/callback/facebookCopy credentials to .env
Find the App ID and App Secret in Settings → Basic:
FACEBOOK_CLIENT_ID=123456789012345
FACEBOOK_CLIENT_SECRET=abc123def456...
FACEBOOK_REDIRECT_URI=http://localhost:5000/auth/oauth/callback/facebookFacebook Login requires HTTPS redirect URIs in production. Localhost is only allowed during development.
Using OAuth in the Frontend#
Trigger the OAuth flow by redirecting the user to the backend:
// Open the OAuth consent screen
window.location.href = "http://localhost:5000/auth/oauth/google";
// Or dynamically:
const handleOAuth = (provider: "google" | "github" | "facebook") => {
window.location.href = `${API_URL}/auth/oauth/${provider}`;
};After the OAuth provider redirects back, the user lands at /auth/callback?code=... in the frontend. The callback page extracts the one-time code and exchanges it:
const code = searchParams.get("code");
const { data } = await api.post("/auth/oauth/exchange", { code });
if (data.data.mfaRequired) {
// Store temp token and redirect to MFA challenge
setMfaTempToken(data.data.tempToken);
router.push("/mfa");
} else {
// Store access token and redirect to app
setAccessToken(data.data.accessToken);
router.push("/");
}Adding a New Provider#
AuthHero uses the Strategy Pattern, so adding a new provider only requires implementing the OAuthProvider interface:
interface OAuthProvider {
getAuthUrl(state: string): string;
getAccessToken(code: string): Promise<string>;
getUserProfile(accessToken: string): Promise<OAuthUserProfile>;
}Then register the provider in the service map:
// 1. Create src/modules/auth/oauth/providers/twitter.provider.ts
export class TwitterProvider implements OAuthProvider {
getAuthUrl(state: string) { /* ... */ }
async getAccessToken(code: string) { /* ... */ }
async getUserProfile(accessToken: string) { /* ... */ }
}
// 2. Add to the service map in oauth.service.ts
const providers = {
google: new GoogleProvider(),
github: new GithubProvider(),
facebook: new FacebookProvider(),
twitter: new TwitterProvider(), // ← new
};
// 3. Update SupportedProvider type
type SupportedProvider = "google" | "github" | "facebook" | "twitter";
// 4. Add env vars: TWITTER_CLIENT_ID, TWITTER_CLIENT_SECRET, TWITTER_REDIRECT_URIEnvironment Variables Summary#
| Provider | Variables Needed |
|---|---|
Google | GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI |
GitHub | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_REDIRECT_URI |
Facebook | FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET, FACEBOOK_REDIRECT_URI |
All OAuth variables are optional. If not set, the corresponding provider returns a clear error:
{
"success": false,
"message": "OAuth provider \"twitter\" is not configured. Check your environment variables."
}