Skip to main content

Integration with FxA

Last updated: March 18th, 2026

Overview

Mozilla accounts integration is available for Mozilla groups on request using OpenID Connect (OIDC) and OAuth 2.0. Your service becomes a Relying Party (RP) that authenticates users through Mozilla accounts.

note

This tutorial covers integration steps. You must also meet ongoing integration requirements to maintain uninterrupted service.

What You Need to Provide

Before you can integrate, gather the following information:

ItemDescriptionRequired
OAuth Redirect URLsWhere FxA redirects after authentication (one for stage, one for production)Yes
Webhook URLsEndpoint to receive account events (password changes, deletions, etc.)Yes
Service IconDisplayed in users' Connected Services list. Confirm current specs with the FxA team.No
Technical ContactEmail for API changes and critical updatesYes
Expected TrafficRough estimate of authentication volumeYes
Integration TypeWeb app, native app, browser, API, or extensionYes

Quick Start (for experienced OAuth/OIDC developers)

If you're familiar with OAuth 2.0 and OIDC:

  1. File a Jira issue in the FXA project requesting OAuth credentials (include info from the table above)
  2. Join the firefox-accounts-notices group for updates
  3. Use staging endpoints for development:
    • Authorization: https://accounts.stage.mozaws.net/authorization
    • Token: https://oauth.stage.mozaws.net/v1/token
    • Profile: https://profile.stage.mozaws.net/v1/profile
  4. Implement standard OIDC authorization code flow
  5. Set up webhook handler for account events
  6. Request production credentials when ready

Discovery document: https://accounts.stage.mozaws.net/.well-known/openid-configuration

How the Flow Works

Step-by-Step Integration Guide

Step 1: Request OAuth Credentials

File an issue in the FXA project in Mozilla's Jira with:

Required Information:

  • OAuth redirect URLs (stage and production)
  • Webhook notification URL
  • Integration type (web app, native app, etc.)
  • Technical contact email
  • Expected traffic estimate
  • Service icon

Tell Us About Your Needs:

  • Do you need ongoing access to profile data when users aren't logged in? (requires refresh tokens with access_type=offline)
  • Do you need to write profile data? (only avatar and displayName are writable via the API)
  • Do you need encryption keys derived from the user's password? (scoped keys - note these change if the user changes their password)
  • Will this be a subscription/paid service?
  • Will you have subscription lead/marketing pages?

Most integrations are Relying Parties (user-facing apps where users log in). If you're building an API that other services call using tokens, you may be a Resource Server - see the distinction below.

You'll receive:

  • client_id - public identifier for your service
  • client_secret - private secret for backend token exchanges (never expose publicly or commit to repositories)

Note: Request separate credentials for each platform (e.g., web, iOS, Android).

Step 2: Implement the Authorization Flow

Build the authorization URL with these parameters:

ParameterRequiredDescription
client_idYesYour OAuth client ID
scopeYesSpace-separated scopes (usually profile)
stateYesYour random state token
redirect_uriYesMust match registered redirect URL
response_typeYesUse code
code_challengeNoOnly needed if using PKCE. (SHA256 hash of verifier)
code_challenge_methodNoOnly needed if using PKCE. Only S256 is supported
access_typeRecommendedonline or offline (offline gives refresh tokens)
actionRecommendedemail or force_auth
entrypointRecommendedMetrics identifier (coordinate with FxA team)
utm_campaignNo
utm_sourceNo
utm_mediumNo
utm_termNo

Step 3: Set Up Webhook Handler

FxA sends Security Event Tokens (SET) via webhooks when users change passwords, update profiles, change subscriptions, or delete accounts. You must handle these events.

Register Your Webhook

Create a pull request in cloudops-infra (FxA can help with this if needed):

Add your client_id to endpoint_topic_config and webhook URL to endpoint_subscription_config. See example PR.

Verify and Handle Events

Webhooks are JWTs signed by FxA. Verify them using FxA's public keys from the JWKS endpoint (found via jwks_uri in the discovery document). Here is an example in typescript:

import jwt from 'jsonwebtoken';
import jwkToPem from 'jwk-to-pem';

// Fetch and cache these at startup from the jwks_uri
let publicJwks: Array<{ kid: string; [key: string]: any }>;

// Your client_id, provided when you registered your OAuth credentials
const CLIENT_ID = 'your_client_id';

async function verifyWebhook(authHeader: string): Promise<object> {
if (!authHeader?.startsWith('Bearer ')) {
throw new Error('Invalid authorization header');
}

const token = authHeader.slice(7);
const decoded = jwt.decode(token, { complete: true });

if (!decoded || typeof decoded === 'string') {
throw new Error('Invalid token');
}

const jwk = publicJwks.find(j => j.kid === decoded.header.kid);
if (!jwk) {
throw new Error(`Unknown key ID: ${decoded.header.kid}`);
}

return jwt.verify(token, jwkToPem(jwk), {
algorithms: ['RS256'],
issuer: 'https://accounts.firefox.com',
audience: CLIENT_ID,
});
}

app.post('/webhook', async (req, res) => {
try {
const event = await verifyWebhook(req.headers.authorization);

// Handle the event based on type
// Events: password-change, profile-change, subscription-state-change, delete-user

res.status(200).send('OK');
} catch (error) {
console.error('Webhook verification failed:', error);
res.status(401).send('Unauthorized');
}
});

Important: Resource Servers must return 200 even for unknown users. See event broker documentation for event formats.

Step 4: Test on Staging

note

Use staging servers for development. The staging database is persistent. Clean up test accounts when done - if using PyFxA, use destroy_account().

Verify:

  • Users can authenticate and your app receives profile data
  • Refresh tokens work (if using access_type=offline)
  • Webhooks are received and processed correctly
  • Error cases are handled gracefully

Production Checklist

Before going live:

  • Request production OAuth credentials via your Jira issue
  • Use production endpoints:
    • Discovery: https://accounts.firefox.com/.well-known/openid-configuration
    • OAuth: https://oauth.accounts.firefox.com/
  • Register production webhook URL
  • Submitted your service icon
  • Joined firefox-accounts-notices mailing list

Reference

Profile Data

Mozilla accounts stores minimal identity data:

FieldDescription
uidStable user identifier
emailUser's email address
localeBrowser locale at account creation
displayNameOptional display name
avatarOptional profile image URL

Scopes

Most integrations need only scope=profile. For advanced scopes (Resource Servers, Sync access), see OAuth scopes documentation.

Relying Party vs Resource Server

Relying PartyResource Server
What it isUser-facing app with loginAPI accessed by other services
User sees login?YesNo
Appears in Connected Services?Yes, as distinct entryNo (shows as parent service)
Receives ALL account events (not just users who have signed in to that specific service)?NoYes
ExamplesWebsites, appsSync, Relay APIs

Most integrations are Relying Parties. Resource Servers are typically internal Mozilla services accessed via Firefox's OAuth token.