OAuth

Add social sign-in with Google and Apple using the Assent library. Users can sign in with OAuth providers, link multiple providers to their account, and manage connected accounts from settings.

v1.8.3
Level: Medium
12
514
4

Install Elixir deps

The feature uses Assent , a flexible OAuth/OIDC library that supports many providers out of the box. Assent handles the OAuth flow, token management, and user info extraction.

Runtime configuration

OAuth providers are configured in runtime.exs for production, reading credentials from environment variables:

For development, create config/dev.secret.exs with your test credentials and import it from config/dev.exs .

Accounts context - OAuth functions

The Accounts context is extended with OAuth-related functions:

oauth_provider_configured?/1 - Checks if a provider is configured in the application config. Used to conditionally show OAuth buttons in the UI.

find_or_create_oauth_user/3 - The main OAuth authentication function with a three-step strategy:

OAuth users are automatically confirmed since their email is pre-verified by the provider.

list_user_identities/1 - Lists all OAuth identities for a user, ordered by provider name.

unlink_identity/2 - Removes an OAuth provider from a user's account. Includes a safety check: users can only unlink if they have a password set OR have other identities remaining, preventing account lockout.

User schema update

The User schema gets a has_many :identities association to UserIdentity . This allows loading all connected OAuth providers for a user.

UserIdentity schema

The UserIdentity schema stores OAuth provider connections for users. Each identity links a user to a specific provider (like "google" or "apple") using the provider's unique identifier ( provider_uid ).

The schema also stores the provider_email (which may differ from the user's account email) and provider_data (the raw user info from the OAuth provider, useful for debugging or future features).

A unique constraint on [:provider, :provider_uid] ensures each OAuth account can only be linked to one user.

OAuth button components

Brand-compliant OAuth buttons following official guidelines from Google and Apple:

Both buttons use the official SVG icons and follow the respective brand guidelines for colors and styling.

OAuth controller

The OAuthController handles the OAuth flow with two actions:

request/2 - Initiates the OAuth flow by generating an authorization URL using Assent and redirecting the user to the provider. Stores session params (for CSRF protection) in the session.

callback/2 - Handles the OAuth callback when the user returns from the provider. Exchanges the authorization code for tokens, extracts user info, and calls find_or_create_oauth_user/3 to authenticate. On success, logs the user in with "remember me" enabled.

The controller uses String.to_existing_atom/1 when parsing the provider parameter, which safely rejects unknown providers.

Login LiveView

The login page conditionally displays OAuth buttons when providers are configured. The buttons appear above the email/password form with an "or continue with email" divider.

The mount/3 callback checks which providers are configured using oauth_provider_configured?/1 and assigns boolean flags ( google_oauth? , apple_oauth? ) to control button visibility.

Registration LiveView

Similar to the login page, registration shows OAuth buttons when configured. The divider text reads "or register with email" to match the registration context.

Settings LiveView - Connected accounts

The settings page adds a "Connected Accounts" section showing:

The can_unlink assign determines whether unlink buttons appear. Users can unlink if they have a password OR more than one identity.

The handle_event("unlink_identity", ...) callback processes unlink requests, verifies sudo mode, and updates the UI after successful unlinking.

Router configuration

OAuth routes are added in their own scope under /auth :

The routes use dynamic :provider segments, supporting any configured provider without additional routing changes.