Skip to content

Google OAuth

Loquent supports Google OAuth 2.0 via the authorization code flow. A single callback handler manages login, signup, invitation acceptance, and auto-linking of existing email accounts. The frontend provides a reusable sign-in button that appears on all authentication pages.

Browser → get_google_auth_url_api → Google consent screen
→ Google redirects to /auth/google/callback
→ Token exchange + ID token decode
→ Smart user routing (login / link / signup)
→ Session cookie → redirect to app

Google OAuth credentials are stored in the core_conf table (not environment variables), making them configurable per deployment from the admin panel.

ColumnTypeNotes
idUUIDPrimary key
user_idUUIDFK to user.id, unique, cascade delete
google_idStringGoogle’s sub claim, unique
emailStringGoogle email
nameOption<String>Display name
picture_urlOption<String>Profile picture URL
created_atTimestamptz
updated_atTimestamptz

Two new columns store the OAuth credentials:

  • google_oauth_client_id — your Google Cloud client ID
  • google_oauth_client_secret — the corresponding client secret

Configure these in Settings → System Config in the admin panel.

POST /auth/google/url generates the Google consent URL.

// Request
{
invitation_token: Option<String>,
organization_name: Option<String>,
}
// Response — (auth_url, csrf_token)
("https://accounts.google.com/o/oauth2/v2/auth?...", "a1b2c3d4...")

The server loads credentials from core_conf, generates a CSRF token (UUID v4), and encodes an OAuthFlowState as base64 in the state parameter. The frontend stores the CSRF token in a google_oauth_csrf cookie before redirecting.

GET /auth/google/callback is a raw Axum handler (not a Dioxus server function) because it needs direct access to query parameters and cookies from Google’s redirect.

  1. CSRF validation — Decodes the state parameter, extracts the CSRF token, and compares it against the google_oauth_csrf cookie. Returns 403 on mismatch.

  2. Token exchange — POSTs the authorization code to https://oauth2.googleapis.com/token with the client credentials. Receives an access_token and id_token (JWT).

  3. ID token decode — Extracts the JWT payload (no signature verification needed — the token comes directly from Google over HTTPS with the client secret).

  4. User routing — Three scenarios:

    ScenarioConditionAction
    Logingoogle_account exists by google_idFind user, create session
    Auto-linkemail_password_account exists by emailCreate google_account linked to that user
    SignupNo matching accountCreate user + google_account, then create org or process invitation
  5. Session creation — Sets session_token cookie (HttpOnly, Secure) and clears the CSRF cookie. Redirects to /.

All failures redirect to /login?error=Something+went+wrong.... If a new user or organization was partially created, the handler deletes the records to prevent orphaned data.

All types live in src/bases/auth/types/google_oauth_types.rs:

// Encoded as base64 in the state query parameter
struct OAuthFlowState {
csrf_token: String,
organization_name: Option<String>,
invitation_token: Option<String>,
}
// Deserialized from Google's token endpoint response
struct GoogleTokenResponse {
access_token: String,
id_token: String, // JWT containing user claims
token_type: String,
expires_in: u64,
}
// Decoded from the id_token JWT payload
struct GoogleIdTokenClaims {
sub: String, // Google user ID
email: String,
name: Option<String>,
picture: Option<String>,
}
FilePurpose
src/bases/auth/api/get_google_auth_url_api.rsGenerates authorization URL
src/bases/auth/api/google_callback_handler.rsHandles Google’s redirect callback
src/bases/auth/types/google_oauth_types.rsOAuth data types
src/bases/auth/constants/google_oauth_constants.rsURLs and cookie names
src/bases/auth/conf/core/google_oauth_core_conf.rsLoads credentials from core_conf
migration/src/m20260317_120000_create_google_account_table.rsgoogle_account migration
migration/src/m20260317_130000_core_conf_add_google_oauth_fields.rscore_conf credential columns
src/shared/components/google_sign_in_button_component.rsReusable Google sign-in button
src/bases/auth/types/session_type.rsSession type with has_password_account flag
src/shared/types/client_session_type.rsClient-side session type

The GoogleSignInButton component (src/shared/components/google_sign_in_button_component.rs) is a reusable Dioxus component that handles the entire client-side OAuth redirect flow.

PropTypeDefaultPurpose
invitation_tokenOption<String>NonePassed through to the callback for invitation acceptance
organization_nameOption<String>NoneOrg name from the signup form
labelString"Continue with Google"Button text
  1. User clicks the button → calls get_google_auth_url_api with the optional invitation_token and organization_name
  2. Receives (auth_url, csrf_token) from the server
  3. Sets the google_oauth_csrf cookie via JavaScript (max-age 600s, SameSite=Lax)
  4. Redirects the browser to auth_url

The button renders with the official Google “G” icon and shows a loading spinner during the redirect.

  • Login page (login_card_component.rs) — standard sign-in
  • Signup page (signup_card_component.rs) — passes organization_name
  • Invitation acceptance (accept_invitation_card_component.rs) — passes invitation_token

When a user accepts an invitation via Google OAuth, the callback handler verifies that the Google account’s email matches the invitation email. If they don’t match, the handler redirects back to the invitation page with an error:

“This invitation was sent to {email}. Please sign in with that Google account instead.”

This prevents users from accepting invitations with a different Google account than the one the invitation was sent to.

The Session and ClientSession types include a has_password_account: bool field that indicates whether the user has an email/password account linked. This enables conditional UI behavior:

  • OAuth-only users (has_password_account: false) — the Account tab in Settings is hidden since there’s no password to manage. The default Settings tab falls back to Notifications.
  • Email+password users (has_password_account: true) — the Account tab is visible with email and password management.

The admin system config service (src/mods/admin/services/admin_system_config_service.rs) exposes Google OAuth credentials for get/update operations. Provider health checks validate that credentials are present and track verification status via audit logs with the provider.verify.google_oauth action.