Getting Started

Getting Started with EmbedAuth

Add a complete, hosted authentication UI to any web app with an iframe and a few lines of JavaScript — then verify tokens on your server.

3 min readUpdated October 9, 2026

EmbedAuth gives your application a full authentication experience — sign in, sign up, password reset, magic links, OTP codes, and OAuth — without you building or maintaining any of it. You drop an iframe into your page, listen for a single event, and receive a signed JWT you can trust on your backend.

This guide takes you from an empty page to a working, verified sign-in in about five minutes.

Prerequisites

  • An EmbedAuth account and an app created in the dashboard. Each app has its own clientId, allowed domains, and theme.
  • A page served over HTTPS (localhost is fine for development).
  • A backend that can verify a JWT — any language works, and later guides cover Node, Python, and Go.

Step 1 — Create an app and add your domain

In the dashboard, create a new app. On the app's Domains page, add the domain your page is served from — the bare hostname, such as app.yoursite.com, without https:// or a path. An entry matches that exact host, not its subdomains, so add each one you embed on.

The widget will still render on a site that is not on the list, but it will not hand that site any tokens: the auth-success message is posted only to a page on one of your domains. That is what stops another site that copies your embed code from receiving your users' tokens. Until an app has at least one domain, tokens go to whichever page frames the widget, so add yours before you go live.

Copy the app's clientId. You will use it in the iframe URL.

Step 2 — Add the iframe

Place the embed anywhere in your markup. The mode parameter selects which form appears first.

<iframe
  id="authframe"
  src="https://embedauth.com/embed/YOUR_CLIENT_ID?mode=signin"
  width="420"
  height="600"
  frameborder="0"
  style="border: none;"
></iframe>

The embed is fully responsive and reports its own height (see PostMessage Events), so you can size the frame dynamically instead of hard-coding 600.

Step 3 — Listen for the result

The iframe talks to your page through window.postMessage. When authentication succeeds you receive a JWT, a refresh token and the user's profile. Always verify event.origin first — this is the single most important line in your integration.

The origin to compare against is https://cdn.embedauth.com, not https://embedauth.com: the iframe URL above redirects to the widget's copy on EmbedAuth's CDN, and messages come from the page that actually loaded.

<script>
  window.addEventListener('message', (event) => {
    if (event.origin !== 'https://cdn.embedauth.com') return;

    if (event.data.type === 'authframe:auth-success') {
      const { token, user } = event.data.data;
      // Hand the token to your backend, or store it for API calls
      sessionStorage.setItem('authframe_token', token);
      window.location.href = '/dashboard';
    }
  });
</script>

That is a complete client integration. But the token is only meaningful once your server confirms it is genuine.

Step 4 — Verify the token on your server

The JWT is signed with RS256, an asymmetric algorithm. EmbedAuth holds the private key; you verify with the matching public key, published at a JWKS endpoint:

https://embedauth.com/.well-known/jwks.json?clientId=YOUR_CLIENT_ID

Because verification uses a public key, your server never needs a shared secret. A minimal Node example:

import { createRemoteJWKSet, jwtVerify } from 'jose';

const JWKS = createRemoteJWKSet(
  new URL('https://embedauth.com/.well-known/jwks.json?clientId=YOUR_CLIENT_ID')
);

export async function verifyToken(token) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: 'https://embedauth.com',
    audience: 'YOUR_CLIENT_ID',
  });
  return payload; // { sub, email, name, clientId, iat, exp }
}

Full backend walkthroughs live in Verifying JWTs in Node.js, Python, and Go.

What's in the token

ClaimMeaning
issThe issuer, https://embedauth.com
audYour app's client ID
subStable end-user ID — use this as your foreign key
emailThe user's email address
name / avatarDisplay name and avatar URL, if known
clientIdYour app's client ID again, for convenience
authMethodHow the user signed in, such as email_password or magic_link
sidThe session the token belongs to; the same across refreshes of one sign-in
iat / expIssued-at and expiry timestamps; access tokens last one hour by default

Never trust these values until jwtVerify (or your language's equivalent) has succeeded. A JWT is only a claim; the signature is what makes it a fact.

Next steps