HelloJohn / docs
Self-Hosting

OAuth Providers

Configure third-party OAuth and social login providers (Google, GitHub, Microsoft, etc.) for self-hosted HelloJohn.

OAuth Providers

HelloJohn supports OAuth 2.0 / OIDC social login with popular providers. This page covers how to create OAuth apps with each provider and configure them in HelloJohn.


How Social Login Works

  1. User clicks "Sign in with Google" (or any provider)
  2. HelloJohn redirects to the provider's authorization URL
  3. User authenticates with the provider
  4. Provider redirects back to HelloJohn with an authorization code
  5. HelloJohn exchanges the code for tokens and fetches the user's profile
  6. HelloJohn creates or links the user account, issues a session

Callback URL

When registering your app with an OAuth provider, use this callback URL:

https://your-hellojohn-domain.com/v1/oauth/callback/{provider}

Examples:

https://auth.example.com/v1/oauth/callback/google
https://auth.example.com/v1/oauth/callback/github
https://auth.example.com/v1/oauth/callback/microsoft

Configuring Providers

Set provider credentials as environment variables. You can also configure them via the Admin API or dashboard.

Google

  1. Go to Google Cloud Console → APIs & Services → Credentials
  2. Create an OAuth 2.0 Client ID (Web application)
  3. Add your callback URL to Authorized redirect URIs
  4. Copy the Client ID and Client Secret
HELLOJOHN_OAUTH_GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
HELLOJOHN_OAUTH_GOOGLE_CLIENT_SECRET=GOCSPX-your_client_secret
HELLOJOHN_OAUTH_GOOGLE_ENABLED=true

Scopes requested: openid email profile

GitHub

  1. Go to GitHub Developer Settings → OAuth Apps → New OAuth App
  2. Set Authorization callback URL to your HelloJohn callback URL
  3. Copy the Client ID and generate a Client Secret
HELLOJOHN_OAUTH_GITHUB_CLIENT_ID=Ov23liYourClientId
HELLOJOHN_OAUTH_GITHUB_CLIENT_SECRET=your_github_client_secret
HELLOJOHN_OAUTH_GITHUB_ENABLED=true

Scopes requested: read:user user:email

GitHub users may have private emails. HelloJohn fetches the primary email via the /user/emails endpoint automatically.

Microsoft / Azure AD

  1. Go to Azure Portal → Azure Active Directory → App registrations → New registration
  2. Set Redirect URI (Web) to your callback URL
  3. Under Certificates & secrets, create a Client Secret
  4. Copy the Application (client) ID and Directory (tenant) ID
HELLOJOHN_OAUTH_MICROSOFT_CLIENT_ID=your_application_client_id
HELLOJOHN_OAUTH_MICROSOFT_CLIENT_SECRET=your_client_secret_value
HELLOJOHN_OAUTH_MICROSOFT_TENANT_ID=common   # or your specific tenant ID
HELLOJOHN_OAUTH_MICROSOFT_ENABLED=true

Set TENANT_ID to common to allow any Microsoft account, or to a specific Azure AD tenant ID to restrict to your organization.

Scopes requested: openid email profile

Apple

Apple requires additional setup — you need an Apple Developer account.

  1. Create an App ID with Sign in with Apple capability
  2. Create a Service ID (this is your OAuth client)
  3. Generate a private key (.p8 file) — download it once
  4. Configure your domain and callback URLs in the Service ID
HELLOJOHN_OAUTH_APPLE_CLIENT_ID=com.example.your.service.id
HELLOJOHN_OAUTH_APPLE_TEAM_ID=YOURTEAMID
HELLOJOHN_OAUTH_APPLE_KEY_ID=YOURKEYID
HELLOJOHN_OAUTH_APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
HELLOJOHN_OAUTH_APPLE_ENABLED=true

The private key is the content of the .p8 file. Use \n for line breaks when setting as an environment variable.

Apple does not return the user's name or email after the first sign-in. HelloJohn stores this on first sign-in and uses it for subsequent logins.

Discord

  1. Go to Discord Developer Portal → New Application
  2. Under OAuth2, add your callback URL to Redirects
  3. Copy the Client ID and Client Secret
HELLOJOHN_OAUTH_DISCORD_CLIENT_ID=your_discord_client_id
HELLOJOHN_OAUTH_DISCORD_CLIENT_SECRET=your_discord_client_secret
HELLOJOHN_OAUTH_DISCORD_ENABLED=true

Scopes requested: identify email

LinkedIn

  1. Go to LinkedIn Developer Portal → Create App
  2. Under Auth, add your callback URL to Authorized redirect URLs
  3. Copy the Client ID and Client Secret
HELLOJOHN_OAUTH_LINKEDIN_CLIENT_ID=your_linkedin_client_id
HELLOJOHN_OAUTH_LINKEDIN_CLIENT_SECRET=your_linkedin_client_secret
HELLOJOHN_OAUTH_LINKEDIN_ENABLED=true

Scopes requested: openid profile email


Configuring via Admin API

Alternatively, configure providers via the Admin API (useful for multi-tenant setups where each tenant has different OAuth apps):

curl -X PUT "https://api.hellojohn.dev/v1/admin/oauth/providers/google" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "client_id": "your_google_client_id.apps.googleusercontent.com",
    "client_secret": "GOCSPX-your_client_secret"
  }'

Account Linking

When a user signs in with OAuth and the provider email matches an existing account:

ScenarioDefault Behavior
New user, new emailCreate new account
Existing email, same providerSign in to existing account
Existing email, different providerLink to existing account (configurable)

Configure linking behavior:

# Allow linking different OAuth providers to the same account
HELLOJOHN_OAUTH_AUTO_LINK=true

# Require explicit link confirmation (more secure)
HELLOJOHN_OAUTH_AUTO_LINK=false

Allowed Email Domains

Restrict social login to specific email domains (e.g., company SSO):

curl -X PATCH "https://api.hellojohn.dev/v1/admin/config" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "oauth_allowed_domains": ["example.com", "example.org"]
  }'

Users signing in with OAuth emails outside these domains will receive an error.


Frontend Integration

Use the React SDK to add social login buttons:

import { useAuth } from "@hellojohn/react";

function SocialLogin() {
  const { signInWithOAuth } = useAuth();

  return (
    <div>
      <button onClick={() => signInWithOAuth({ provider: "google" })}>
        Sign in with Google
      </button>
      <button onClick={() => signInWithOAuth({ provider: "github" })}>
        Sign in with GitHub
      </button>
      <button onClick={() => signInWithOAuth({ provider: "microsoft" })}>
        Sign in with Microsoft
      </button>
    </div>
  );
}

signInWithOAuth redirects to the provider and returns when the flow completes.


Accessing OAuth Profile Data

After sign-in, the user's connected OAuth profile is available:

const { user } = useUser();

// List all connected OAuth providers
const connections = user.oauthConnections;
// [{ provider: "google", provider_user_id: "...", email: "..." }]

On the backend:

curl "https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456/oauth-connections" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321"

Troubleshooting

redirect_uri_mismatch

The callback URL registered in the provider does not match what HelloJohn is sending. Verify:

  • The callback URL in the provider console exactly matches: https://your-domain.com/v1/oauth/callback/{provider}
  • No trailing slashes
  • The scheme is https:// (not http://)

invalid_client

Client ID or Client Secret is incorrect. Regenerate and update your environment variables.

User gets email_not_provided

Some providers require additional scopes or settings to share the email address:

  • GitHub: Users with private emails must grant email access
  • Twitter/X: Email is gated behind Elevated API Access
  • Discord: Ensure the email scope is requested

Apple Sign-in fails locally

Apple requires HTTPS and a real domain. Use a tunnel like ngrok or Cloudflare Tunnel for local development.


On this page