Vanilla JS
Vanilla JS Example
Section titled “Vanilla JS Example”This guide shows how to implement the MC-ID authentication flow using plain JavaScript and HTTP requests. This is useful for understanding the underlying OAuth 2.1/OIDC flow or for simple applications without a framework.
Prerequisites
Section titled “Prerequisites”- Client ID: Your application’s Client ID.
- Client Secret: Your application’s Client Secret.
- Redirect URI: The URL where MC-ID will redirect users after login.
Helper Functions
Section titled “Helper Functions”First, you’ll need these helper functions to generate the PKCE code verifier and challenge:
-
Add PKCE Helper Functions
Add these utility functions to your application. They generate the cryptographic values required for PKCE; or provide your own implementations.
// Generate a random code verifier (43-128 characters)function generateCodeVerifier() {const array = new Uint8Array(32);crypto.getRandomValues(array);return base64UrlEncode(array);}// Generate the code challenge from the verifier (S256 method)async function generateCodeChallenge(verifier) {const encoder = new TextEncoder();const data = encoder.encode(verifier);const digest = await crypto.subtle.digest("SHA-256", data);return base64UrlEncode(new Uint8Array(digest));}// Base64url encode (RFC 4648)function base64UrlEncode(buffer) {return btoa(String.fromCharCode(...buffer)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");}// Generate a random state for CSRF protectionfunction generateState() {const array = new Uint8Array(16);crypto.getRandomValues(array);return base64UrlEncode(array);} -
Start the Authorization Flow
Generate the PKCE values, store them, and redirect the user to MC-ID.
const clientId = "YOUR_CLIENT_ID";const redirectUri = "http://localhost:3000/callback";const scope = "openid profile email connections";async function startAuth() {// Generate PKCE valuesconst codeVerifier = generateCodeVerifier();const codeChallenge = await generateCodeChallenge(codeVerifier);const state = generateState();// Store verifier and state for the callbacksessionStorage.setItem("code_verifier", codeVerifier);sessionStorage.setItem("oauth_state", state);// Build the authorization URLconst authUrl = new URL("https://mc-id.com/api/auth/oauth2/authorize");authUrl.searchParams.append("client_id", clientId);authUrl.searchParams.append("redirect_uri", redirectUri);authUrl.searchParams.append("response_type", "code");authUrl.searchParams.append("scope", scope);authUrl.searchParams.append("state", state);authUrl.searchParams.append("code_challenge", codeChallenge);authUrl.searchParams.append("code_challenge_method", "S256");// Redirect the userwindow.location.href = authUrl.toString();} -
Handle the Callback
On your callback page, verify the state parameter and extract the authorization code.
// On your callback pageconst urlParams = new URLSearchParams(window.location.search);const code = urlParams.get("code");const returnedState = urlParams.get("state");// Verify state to prevent CSRF attacksconst savedState = sessionStorage.getItem("oauth_state");if (returnedState !== savedState) {throw new Error("State mismatch - possible CSRF attack");}// Get the code verifier we saved earlierconst codeVerifier = sessionStorage.getItem("code_verifier");if (code && codeVerifier) {exchangeCodeForToken(code, codeVerifier);}// Clean upsessionStorage.removeItem("code_verifier");sessionStorage.removeItem("oauth_state"); -
Exchange Code for Tokens
Send the code and the original code verifier to the token endpoint.
async function exchangeCodeForToken(code, codeVerifier) {const tokenEndpoint = "https://mc-id.com/api/auth/oauth2/token";const clientId = "YOUR_CLIENT_ID";const clientSecret = "YOUR_CLIENT_SECRET";const redirectUri = "http://localhost:3000/callback";const response = await fetch(tokenEndpoint, {method: "POST",headers: { "Content-Type": "application/x-www-form-urlencoded" },body: new URLSearchParams({grant_type: "authorization_code",code: code,client_id: clientId,client_secret: clientSecret,redirect_uri: redirectUri,code_verifier: codeVerifier // Required for PKCE})});const data = await response.json();console.log("Tokens:", data);// data.access_token - Use this to call the userinfo endpoint// data.id_token - Contains user claims (JWT)// data.refresh_token - Only if you requested offline_access scopeawait getUserInfo(data.access_token);} -
Get User Info
Use the
access_tokento retrieve the user’s profile information from the UserInfo endpoint.async function getUserInfo(accessToken) {const response = await fetch("https://mc-id.com/api/auth/oauth2/userinfo", {headers: {Authorization: `Bearer ${accessToken}`}});const userProfile = await response.json();console.log("User Profile:", userProfile);return userProfile;}Example response (claims depend on requested scopes):
{"sub": "AaltJ3XUoyDQiqDVk865CILljZBXrjZz","name": "Notch","email": "user@example.com","email_verified": true,"accounts": [{"uuid": "069a79f444e94726a5befca90e38aaf5","primary": true,"username": "Notch"}],"connections": [{"providerId": "discord","accountId": "123456789012345678"}]}
Scopes Reference
Section titled “Scopes Reference”See MC-ID Scopes