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.
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:
| Section | What the user can do |
|---|---|
| Profile | See their email address and change their name |
| Password | Change their password, or set a first one if they signed up with a magic link, a code or Google |
| Sessions | See every device signed in to their account and sign any of them out |
| Delete account | Delete 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
| Event | Payload | Sent to | Fires when |
|---|---|---|---|
authframe:account-ready | { clientId } | any parent | The widget is waiting for a token |
authframe:token-expired | {} | any parent | The token it was given was refused |
authframe:account-updated | { user, changes } | the page that sent the token | The user changed their name or password |
authframe:account-deleted | { userId } | the page that sent the token | The user deleted their account |
authframe:tab-change | { tab } | any parent | The user switched tabs |
authframe:resize | { height } | any parent | The 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(withchanges) oruser.deleted(withuserIdandemail) if you subscribe to those events. Useuser.deletedto 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.