Browser transaction
Register https://example.com/auth/callback exactly. Generate a new verifier, S256 challenge, and random state for every attempt. Keep the transaction short-lived and tied to the same browser; validate state before exchanging the code. Never include a client secret in browser code.
const clientId = 'YOUR_CLIENT_ID';
const redirectUri = 'https://example.com/auth/callback';
const encode = bytes => btoa(String.fromCharCode(...bytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const random = () => encode(crypto.getRandomValues(new Uint8Array(32)));
const verifier = random();
const state = random();
const challenge = encode(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))));
sessionStorage.setItem('bhauu_pending', JSON.stringify({ state, verifier }));
const url = new URL('https://auth.bhauu.online/oauth/authorize');
Object.entries({ client_id: clientId, redirect_uri: redirectUri, response_type: 'code', scope: 'profile email', state, code_challenge: challenge, code_challenge_method: 'S256' })
.forEach(([key, value]) => url.searchParams.set(key, value));
location.assign(url);Callback and token exchange
const params = new URL(location.href).searchParams;
const pending = JSON.parse(sessionStorage.getItem('bhauu_pending') || 'null');
sessionStorage.removeItem('bhauu_pending');
if (!pending || !params.get('state') || params.get('state') !== pending.state || !params.get('code')) throw new Error('Invalid OAuth callback');
const body = new URLSearchParams({ grant_type: 'authorization_code', client_id: 'YOUR_CLIENT_ID', code: params.get('code'), redirect_uri: 'https://example.com/auth/callback', code_verifier: pending.verifier });
const response = await fetch('https://auth.bhauu.online/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body });
if (!response.ok) throw new Error('Token exchange failed');
const result = await response.json(); // Use briefly; do not log or persist tokens long-term.
history.replaceState(null, '', '/auth/callback');After the exchange
Call https://auth.bhauu.online/oauth/userinfo using the Bearer access token when you need scoped identity claims. Avoid long-term token storage in the browser; prefer a backend-owned session for durable sign-in. A refresh-grant walkthrough is not part of this stable public contract.
See security and session boundaries.