Federated Credential Management (FedCM) API — a brief primer

data security concept, mobile application access, login and pass

The Federated Credential Management (FedCM) API is a web platform feature designed to modernize how users sign in with an identity provider (IdP) (for example, “Sign in with …”) while improving privacy, security, and user experience compared to older federated-login patterns.

Why it exists

Traditional “Sign in with …” flows often rely on third-party cookies, hidden iframes, and cross-site redirects. As browsers increasingly restrict third-party cookies and cross-site tracking techniques, those legacy approaches become brittle and privacy-sensitive.

FedCM provides a browser-mediated way for a site (the relying party, or RP) to request a federated sign-in from an IdP, with the browser presenting a standardized UI and controlling how identity information is shared.

What it changes

With FedCM:

				
					<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FedCM API Demo</title>
    <link href="style.css" rel="stylesheet" />
    <script src="federatedCredentialManagement_API.js" defer></script>
</head>
    
<body>
    <div class="container">
        <h1>FedCM API Demo (Relying Party)</h1>
        <p>
            This demo simulates a website (Relying Party - RP) initiating a federated sign-in flow
            using the FedCM API. It will attempt to communicate with a hypothetical Identity Provider (IdP).
        </p>
        <p class="warning">
            <strong>Important:</strong> FedCM is an experimental technology. You need a browser that supports it
            (e.g., Chrome, Edge with flags enabled, or Firefox Nightly).
            The `configURL` and `clientId` below are placeholders; a real IdP would provide these.
        </p>
    
        <button id="signInButton">Sign in with FedCM</button>
    
        <div id="status" class="info">
            Click the "Sign in with FedCM" button to begin.
        </div>
    
        <h2>Result:</h2>
        <pre id="result"></pre>
    </div>

</body>

</html>
				
			
				
					body {
    font-family: sans-serif;
    margin: 2em;
    background-color: #f4f4f4;
    color: #333;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

h1 {
    color: #2c3e50;
    text-align: center;
}
button {
    display: block;
    margin: 20px auto;
    padding: 10px 20px;
    font-size: 1em;
    background-color: #3498db;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

button:hover {
    background-color: #2980b9;
}

#status,
#result {
    margin-top: 20px;
    padding: 15px;
    border-radius: 5px;
    background-color: #ecf0f1;
    border: 1px solid #bdc3c7;
    white-space: pre-wrap;
    /* Preserve whitespace and line breaks */
    word-break: break-all;
    /* Break long words */
}
.success {
    background-color: #d4edda;
    border-color: #28a745;
    color: #155724;
}

.error {
    background-color: #f8d7da;
    border-color: #dc3545;
    color: #721c24;
}

.info {
    background-color: #e2e3e5;
    border-color: #6c757d;
    color: #383d41;
}

.warning {
    background-color: #fff3cd;
    border-color: #ffc107;
    color: #856404;
}
				
			
				
					const signInButton = document.querySelector('#signInButton');
const statusDiv = document.querySelector('#status');
const resultPre = document.querySelector('#result');

// Function to update the status and result displays
const updateDisplay = (type, message, data = null) => {
	statusDiv.className = type;
	statusDiv.textContent = message;
	if (data) {
		resultPre.textContent = JSON.stringify(data, null, 2);
	} else {
		resultPre.textContent = '';
	}
};

// Basic check for FedCM availability on page load
if ('credentials' in navigator && 'get' in navigator.credentials) {
	updateDisplay(
		'info',
		'FedCM API appears to be available. Click the button to test. ' +
			'Remember to replace placeholder `configURL` and `clientId`.'
	);
} else {
	updateDisplay(
		'error',
		'FedCM API is not natively supported in this browser environment.'
	);
}

// Add event listener to the sign-in button
signInButton.addEventListener('click', async () => {
	updateDisplay('info', 'Attempting to sign in with FedCM...');
	resultPre.textContent = 'Waiting for FedCM API response...';

	// Check if FedCM API is available in the browser
	if (!('credentials' in navigator) || !('get' in navigator.credentials)) {
		updateDisplay(
			'error',
			'FedCM API not available in this browser. Please use a compatible browser ' +
				'(e.g., Chrome or Edge with experimental flags enabled, or Firefox Nightly).'
		);
		return;
	}

	try {
		// The core of the FedCM API: navigator.credentials.get()
		// This call triggers the browser's FedCM UI to show available accounts
		// from registered Identity Providers (IdPs).
		const credential = await navigator.credentials.get({
			identity: {
				// 'providers' is an array of Identity Provider configurations.
				// In a real application, these would be provided by the IdP.
				providers: [
					{
						// configURL: The URL to the IdP's well-known configuration file
						// (e.g., `https://idp.example/.well-known/web-identity/v1`).
						// This JSON file describes the IdP's endpoints and capabilities.
						// REPLACE WITH A REAL IDP'S CONFIG URL.
						configURL: 'https://idp.example/fedcm.json', // Placeholder URL

						// clientId: Your Relying Party's unique client ID,
						// registered with the Identity Provider.
						// REPLACE WITH YOUR ACTUAL CLIENT ID FROM THE IDP.
						clientId: 'YOUR_RP_CLIENT_ID_GOES_HERE', // Placeholder Client ID

						// nonce: A cryptographically strong, randomly generated string.
						// It's used to prevent replay attacks and is typically sent
						// to the IdP and included in the returned ID token.
						// Recommended for enhanced security.
						nonce: crypto.randomUUID(), // Generates a unique nonce

						// Optional: The 'context' can be 'signin', 'signup', 'use', or 'reload'.
						// This provides a hint to the IdP about the user's intent.
						context: 'signin'
					}
				]
			}
		});

		// Check the type of credential received.
		// For FedCM, it should be an 'IdentityCredential'.
		if (credential.type === 'identity') {
			// An IdentityCredential object contains the ID token.
			const identityCredential = credential;

			updateDisplay(
				'success',
				'Successfully received IdentityCredential from FedCM!',
				{
					id: identityCredential.id,
					protocol: identityCredential.protocol,
					token: identityCredential.token // This is the JWT from the IdP
					// In a real app, you would send this 'token' to your backend
					// for verification and user session creation.
				}
			);
			console.log('Identity Credential:', identityCredential);
			alert(
				'Sign-in successful via FedCM! Check console for details and the received token.'
			);

			// In a real application, you would now send `identityCredential.token`
			// to your backend server for verification and user session establishment.
			// Example (conceptual, requires backend endpoint):
			/*
                    const response = await fetch('/api/verify-fedcm-token', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({ token: identityCredential.token }),
                    });
                    const backendResult = await response.json();
                    console.log('Backend verification result:', backendResult);
                    */
		} else {
			updateDisplay(
				'warning',
				'Received an unexpected credential type: ' + credential.type,
				credential
			);
			console.warn('Unexpected credential type:', credential);
		}
	} catch (error) {
		// Handle various types of errors that can occur during the FedCM flow.
		// These include user cancellation, IdP errors, browser errors, etc.
		updateDisplay(
			'error',
			'FedCM API error: ' + error.name + ' - ' + error.message,
			{
				name: error.name,
				message: error.message
				// If it's an IdentityCredentialError, it might have more details
				// idpError: error.idpError // (Not always present, depends on IdP implementation)
			}
		);
		console.error('FedCM API call failed:', error);
		alert('FedCM sign-in failed. Check the console for error details.');
	}
});

				
			

Benefits at a glance

more posts:
Online video streaming platform and digital content management concept with media player interface, cloud library, and multimedia files on laptop, representing content distribution, video marketing
Code

Breaking into the Pipeline: Real-Time Frame Manipulation with the Insertable Streams for MediaStreamTrack API

The experimental Insertable Streams for MediaStreamTrack API closes a long-standing gap in web multimedia by treating live camera feeds as standard Web Streams. By piping individual VideoFrame objects through a TransformStream and recording the transformed output via MediaRecorder, developers can execute frame-by-frame processing—like real-time filtering, watermarking, and computer vision overlays—without relying on hidden canvas hacks.

Discover More »
Apps & Custom Software

What Building Our Own App Taught Us About Building Yours

When Hess WebTech built and launched Tericipe—an Android app that turns printed recipes into a searchable digital collection—in under three months, we had to live with every decision we usually advise clients on. From testing against real-world messy data and handling AI uncertainty to server-side payment security and post-launch maintenance, here are five crucial lessons from our own build that apply to almost any software project.

Discover More »