Configuration

Account Widget

Let your users manage their own accounts — name, password, signed-in devices and account deletion — with a second embeddable widget you design exactly like the sign-in form.

5 min readUpdated October 9, 2026

The sign-in form gets your users in. The account widget is where they look after their account afterwards: change their name, change or set a password, see the devices signed in to the account and sign them out, and — if you allow it — delete the account.

It is off until you turn it on, and it offers only the parts you choose. You can embed it in your site, or link to it as a page of its own.

Turning it on

Open your app in the dashboard and go to Account Widget. Switch it on and choose what your users can do:

SectionWhat the user can do
ProfileSee their email address and change their name
PasswordChange their password, or set a first one if they signed up with a magic link, a code or Google
SessionsSee every device signed in to their account and sign any of them out
Delete accountDelete their account permanently, after confirming with their password

Profile, Password and Sessions are chosen for you the first time; Delete account is yours to add. A section you leave out is not just hidden: its API endpoint refuses the request too. While the widget is off, both the widget and its API answer 404.

Designing it

Go to Account Design. It is the same editor as Auth Design, with the same controls, presets, custom CSS, element IDs and classes, and the same draft, publish and version history — only the live preview shows the account widget.

The account widget is built from the sign-in form's pieces (.af-card, .af-tabs, .af-input, .af-button-primary and so on), so one design can style both. The first time you turn the widget on, an app that already has a sign-in design starts with that same design, and the Account Design page says the two share it and offers a separate copy. You can also pick Use the sign-in design later. A few controls style account-only elements: the social button colours style its secondary buttons, and the error colour styles the delete button.

Embedding it

Put the frame on a page your users reach once they are signed in:

<iframe
  id="embedauth-account"
  src="https://cdn.embedauth.com/embed/YOUR_CLIENT_ID/account.html"
  width="420"
  height="640"
  style="border:none;border-radius:16px;overflow:hidden"
></iframe>

The widget holds no session of its own. When it loads it asks your page for the user's access token — the token from authframe:auth-success — and your page hands it over:

const ACCOUNT_ORIGIN = 'https://cdn.embedauth.com';
const frame = document.getElementById('embedauth-account');

window.addEventListener('message', async (event) => {
  if (event.origin !== ACCOUNT_ORIGIN || event.source !== frame.contentWindow) return;
  const { type, data } = event.data;

  switch (type) {
    case 'authframe:account-ready':
    case 'authframe:token-expired':
      frame.contentWindow.postMessage(
        { type: 'authframe:account-token', token: await getAccessToken() },
        ACCOUNT_ORIGIN,
      );
      break;
    case 'authframe:account-updated':
      // data.user is the updated user; data.changes is ['name'] or ['password']
      break;
    case 'authframe:account-deleted':
      // The account is gone: sign the user out of your site.
      break;
    case 'authframe:resize':
      frame.style.height = data.height + 'px';
      break;
  }
});

getAccessToken() stands for however your app keeps the token. Your page stays in charge of the session: the widget never refreshes the token it was given. When the token expires it sends authframe:token-expired, and your page refreshes it and sends the new one.

Once the app has domains configured, the widget only accepts a token from a page on one of them, and only sends the user's details back to that page. With no domains configured it accepts a token from any page that frames it, as the sign-in form does.

If your page sends token: null, or sends nothing within two seconds, the widget shows the sign-in form and signs the user in itself.

Linking to it

The same URL works as a page of its own, so a "Manage account" link needs no code at all:

https://embedauth.com/embed/YOUR_CLIENT_ID/account

Opened on its own, the widget shows your app's sign-in form first (with your sign-in methods, minus sign-up), then the account. It keeps that session for the browser tab, so a reload does not sign the user out, and offers a Sign out link that ends the session. Add ?tab=password, ?tab=sessions or ?tab=delete to open on a particular tab.

Events

EventPayloadSent toFires when
authframe:account-ready{ clientId }any parentThe widget is waiting for a token
authframe:token-expired{}any parentThe token it was given was refused
authframe:account-updated{ user, changes }the page that sent the tokenThe user changed their name or password
authframe:account-deleted{ userId }the page that sent the tokenThe user deleted their account
authframe:tab-change{ tab }any parentThe user switched tabs
authframe:resize{ height }any parentThe content height changed

When the widget signed the user in itself, account-updated and account-deleted go to a parent on one of the app's domains, as authframe:auth-success does.

What happens on the server

Every change goes through https://embedauth.com/api/embed/account/YOUR_CLIENT_ID, authenticated with the access token as Authorization: Bearer <token>. EmbedAuth checks the token exactly as your backend does, and also that its session is still live — so a device signed out from the Sessions tab cannot use its access token there again, even before it expires.

  • Changing the password asks for the current one, and signs out every other session.
  • Deleting the account asks for the password, or the email address typed out for an account without one. The account is removed for good, with its sessions, password and linked sign-in providers, and the address is free to sign up again.
  • Each change is recorded in your organization's Audit Logs, and sent to your webhooks (the dashboard's Webhooks page) as user.updated (with changes) or user.deleted (with userId and email) if you subscribe to those events. Use user.deleted to remove the user's data from your own systems. Deliveries are not retried, so treat them as notifications.
  • If your site has its own "Delete account" button, your server can delete the sign-in directly with your client secret. See Deleting Users.

Access tokens now carry a sid claim naming the session they belong to. It is how the widget marks "This device" and keeps the current session when signing out the others; your verifier can ignore it.