The embed library handles all the browser UI for Ave flows without redirecting away from your page. It provides three UI patterns and handles postMessage communication from the Ave iframe.
UI patterns
Inline embed Mount an iframe directly in a container element. Stays in page, no overlay. Good for dedicated auth pages.
Sheet Slides up from the bottom as a fixed modal overlay. Good for triggering login from any page.
Popup Opens a new browser window. Works well on desktop. Falls back to sheet if popup is blocked.
Auth flows
mountAveEmbed(options)
Mounts an Ave auth iframe inside a container element. The iframe stays visible while the user completes login.
function mountAveEmbed ( options : MountAveEmbedOptions ) : {
iframe : HTMLIFrameElement ;
destroy : () => void ;
}
The DOM element that will contain the iframe.
options.scope
string
default: "\"openid profile email\""
Space-separated scopes.
Called when the user completes login. payload.redirectUrl is the callback URL with the authorization code. onSuccess : ( payload ) => {
// Extract code from payload.redirectUrl and exchange it
const url = new URL ( payload . redirectUrl );
const code = url . searchParams . get ( "code" );
}
Called on error. payload.error is the error string, payload.message is a human-readable description.
Called when the user closes the embed without completing auth.
import { mountAveEmbed } from "@ave-id/embed" ;
const { destroy } = mountAveEmbed ({
container: document . getElementById ( "auth-container" ) ! ,
clientId: "YOUR_CLIENT_ID" ,
redirectUri: "https://yourapp.com/callback" ,
scope: "openid profile email" ,
onSuccess : async ({ redirectUrl }) => {
const code = new URL ( redirectUrl ). searchParams . get ( "code" ) ! ;
const tokens = await exchangeCode ({ clientId , redirectUri }, { code , codeVerifier });
// Create your session
},
onError : ({ error , message }) => {
console . error ( "Auth error:" , error , message );
},
onClose : () => {
console . log ( "User closed auth" );
},
});
// When done
destroy ();
openAveSheet(options)
Opens a full-width sheet overlay from the bottom. Non-blocking — the user can dismiss it.
function openAveSheet ( options : OpenAveSheetOptions ) : {
close : () => void ;
iframe : HTMLIFrameElement ;
}
Same options as mountAveEmbed except no container — it mounts to the document body automatically.
import { openAveSheet } from "@ave-id/embed" ;
import { generateCodeVerifier , generateCodeChallenge , exchangeCode } from "@ave-id/sdk" ;
async function loginWithSheet () {
const verifier = generateCodeVerifier ();
const challenge = await generateCodeChallenge ( verifier );
const { close } = openAveSheet ({
clientId: "YOUR_CLIENT_ID" ,
redirectUri: "https://yourapp.com/callback" ,
scope: "openid profile email" ,
codeChallenge: challenge ,
codeChallengeMethod: "S256" ,
onSuccess : async ({ redirectUrl }) => {
close ();
const code = new URL ( redirectUrl ). searchParams . get ( "code" ) ! ;
const tokens = await exchangeCode ({ clientId , redirectUri }, { code , codeVerifier: verifier });
// Create session
},
onError : ({ error }) => {
close ();
showError ( error );
},
});
}
Opens a popup window for Ave auth. Returns null if the browser blocked the popup — always handle that case.
function openAvePopup ( options : OpenAvePopupOptions ) : {
popup : Window ;
close : () => void ;
} | null
Additional options beyond sheet:
Popup window width in pixels.
Popup window height in pixels.
import { openAvePopup } from "@ave-id/embed" ;
const result = openAvePopup ({
clientId: "YOUR_CLIENT_ID" ,
redirectUri: "https://yourapp.com/callback" ,
onSuccess : async ({ redirectUrl }) => {
// Handle success
},
});
if ( ! result ) {
// Popup was blocked — fall back to sheet or redirect
openAveSheet ( /* ... */ );
}
Connector flows
Opens the Connector consent UI in a sheet or popup.
function openAveConnectorSheet ( options : OpenAveConnectorOptions ) : {
close : () => void ;
iframe : HTMLIFrameElement ;
}
The resource scope(s) to request.
options.mode
string
default: "\"user_present\""
Communication mode: "user_present" or "background".
import { openAveConnectorSheet } from "@ave-id/embed" ;
const { close } = openAveConnectorSheet ({
clientId: "YOUR_CLIENT_ID" ,
redirectUri: "https://yourapp.com/callback" ,
resource: "target-resource-key" ,
scope: "resource.read" ,
mode: "user_present" ,
onSuccess : async ({ redirectUrl }) => {
close ();
// Exchange code for source token, then do token-exchange for delegated token
},
onError : ({ error }) => {
close ();
},
});
openAveConnectorRuntime(options)
Mounts a Connector runtime iframe for active connector sessions where the source app communicates with the target resource UI.
function openAveConnectorRuntime ( options : OpenAveConnectorRuntimeOptions ) : {
iframe : HTMLIFrameElement ;
send : ( payload : unknown ) => void ;
destroy : () => void ;
}
The delegated access token from the token-exchange grant.
DOM element to mount the runtime iframe in.
Called when the runtime iframe is ready to receive messages.
Called for events sent from the runtime iframe.
Signing flows
openAveSigningSheet(options)
Opens the signing UI as a sheet overlay.
function openAveSigningSheet ( options : OpenAveSigningSheetOptions ) : {
close : () => void ;
iframe : HTMLIFrameElement ;
}
The signing request ID from createSignatureRequest.
Called when the user approves and signs.
Called when the user explicitly denies the request.
Called when the user closes the sheet without acting.
import { openAveSigningSheet } from "@ave-id/embed" ;
import { createSignatureRequest , verifySignature } from "@ave-id/sdk" ;
// 1. Create request on your server first
const { requestId } = await fetch ( "/api/signing/create" , {
method: "POST" ,
body: JSON . stringify ({ action: "approve_transfer" }),
}). then ( r => r . json ());
// 2. Present signing UI
const { close } = openAveSigningSheet ({
requestId ,
onSigned : async ( payload ) => {
close ();
// Verify and execute the approved action server-side
await fetch ( "/api/signing/confirm" , {
method: "POST" ,
body: JSON . stringify ({ requestId }),
});
},
onDenied : () => {
close ();
showMessage ( "Request was denied" );
},
onClose : () => {
close ();
showMessage ( "Request was cancelled" );
},
});
Same as sheet but in a popup window.
function openAveSigningPopup ( options : OpenAveSigningPopupOptions ) : {
popup : Window ;
close : () => void ;
} | null
Returns null if the popup was blocked. Fall back to sheet.
Security rules
Always validate postMessage event origins. Only trust events from your configured Ave issuer origin (https://aveid.net by default). The embed library handles this internally, but if you listen for message events manually, check event.origin.
Always call destroy() or close() when the component unmounts to remove event listeners and clean up iframes
Handle all three outcomes for every flow: success, error, and close-without-action
Do not use popups as the primary UX on mobile — fall back to sheet
The embed does not work inside sandboxed iframes that restrict credentials or passkey access