Sign in with Microsoft
Your users can sign in with their Microsoft account, personal (Outlook.com, Xbox, Skype) or work and school, instead of choosing a name and seed phrase. It works like Sign in with Google: each user gets their own key, the same one every time they sign in, on any device.
- No PrefsDB account for you or your users. You only need a Microsoft app registration, the one you'd use for "Sign in with Microsoft" anyway.
- Your app, your sign-in screen. Microsoft's sign-in shows your app's name, not PrefsDB's.
- Nothing to remember or lose. There's no seed phrase; signing in again finds the same data.
Ready-made buttons
Sign-in Buttons adds this provider's button, and any of the others, to your page with a few lines, and takes care of the one-time codes and popups shown below. You still need the setup in step 1.
How it works
- Your page asks PrefsDB for a one-time code (
PrefsDB.idTokenNonce()). - Your page opens Microsoft's sign-in with Microsoft's own library, MSAL.js, passing that code.
- The user signs in on Microsoft's screens. Microsoft hands your page a signed proof of who they are, which includes the code.
- Your page passes that proof to
PrefsDB.getkeyWithIdToken()withprovider: "microsoft". PrefsDB checks it with Microsoft's keys and gives you the user's key.
From there it's an ordinary PrefsDB object.
1. Register your app with Microsoft
If your app already has "Sign in with Microsoft", use its registration and skip to step 4 below.
- Open the Microsoft Entra admin center (or Microsoft Entra ID in the Azure portal) and go to App registrations → New registration.
- Give it your app's name. Under Supported account types, choose who may sign in (see Which accounts can sign in below). For most apps that's Accounts in any organizational directory and personal Microsoft accounts. Choose it now if you can: changing it on an existing registration takes an extra step.
- Under Redirect URI, pick Single-page application (SPA) and enter the page your sign-in popup returns to, such as
https://app.example.com/signin-done.html(an empty page on your site works well). - Copy the Application (client) ID. It looks like
aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee. It isn't a secret; it goes in your page.
You don't need a client secret or a certificate for this.
Which accounts can sign in
The Supported account types setting and the authority in your page have to agree. If they don't, Microsoft refuses the sign-in before PrefsDB is involved. PrefsDB itself accepts all four kinds.
| Supported account types | Who can sign in | authority to use |
|---|---|---|
| Any organizational directory and personal Microsoft accounts | Everyone: work, school and personal accounts | https://login.microsoftonline.com/common (the default in the examples) |
| Any organizational directory | Work and school accounts | https://login.microsoftonline.com/organizations |
| Personal Microsoft accounts only | Outlook.com, Hotmail, Xbox and other personal accounts | https://login.microsoftonline.com/consumers |
| This organizational directory only | Your own organization's members | https://login.microsoftonline.com/ followed by your Directory (tenant) ID |
If you only want work and school accounts, you don't need personal accounts at all: choose Any organizational directory and use the organizations authority.
Adding personal accounts to an existing registration. Microsoft makes this a two-step change, and the first step isn't shown in the normal settings:
- Open Manifest in your app's menu. Find
"requestedAccessTokenVersion"inside the"api"section, change its value fromnullto2, and Save. (On the older "AAD Graph" manifest tab, the setting is"accessTokenAcceptedVersion"at the top.) - Now change Supported account types under Authentication (or
"signInAudience"in the manifest, to"AzureADandPersonalMicrosoftAccount") and save again.
If you try step 2 first, Microsoft says "Application must accept Access Token Version 2". This setting doesn't change anything for PrefsDB, which uses only the sign-in proof, not access tokens. A new registration made with personal accounts selected already has it.
Your page must be served over https, or from http://localhost while you develop.
Finding your way around Microsoft's pages
- Where the button is. In the Entra admin center, App registrations is under Identity → Applications. In the Azure portal, search for "App registrations".
- Which ID to copy. After you click Register, your app's Overview page lists three IDs. You need Application (client) ID. "Directory (tenant) ID" and "Object ID" won't work.
- Sign-in fails with
AADSTS9002326. Your return page was added as a Web address instead of a Single-page application one. Open Authentication in your app's menu, remove the Web entry and add the same address under "Single-page application". - "The client does not exist or is not enabled for consumers". Someone signed in with a personal Microsoft account, and your registration doesn't accept personal accounts. Either add them (see Which accounts can sign in), or use the
organizationsauthority so Microsoft only offers work and school accounts. If personal accounts are already allowed, check that you copied the Application (client) ID. - "The provided value for the input parameter 'redirect_uri' is not valid". The return page your page sent isn't registered exactly as sent. Microsoft compares every character:
https,www.or not, the path, and a trailing slash. The sign-in window's address shows what was sent afterredirect_uri=(%3A%2F%2Fstands for://). Add that address under Single-page application. - Sign-in fails with
AADSTS50194. Your registration accepts only your own organization, but your page uses thecommonauthority. Usehttps://login.microsoftonline.com/followed by your Directory (tenant) ID instead. - Changes take a minute. After saving a change in Entra, wait a minute or two before trying again.
- More than one site. Add each site's return page as another Single-page application address on the same registration, or register each site separately.
- Using a personal Microsoft account? Microsoft may not let you register apps until your account has a directory. Signing up for a free Azure account creates one.
2. Add sign-in to your page
<script src="https://cdn.jsdelivr.net/npm/@azure/msal-browser@4.30.0/lib/msal-browser.min.js"></script>
<script src="https://prefsdb.com/prefsdb.v1.min.js"></script>
<button id="signin">Sign in with Microsoft</button>
<script>
const msalApp = new msal.PublicClientApplication({
auth: {
clientId: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
authority: "https://login.microsoftonline.com/common", // see "Which accounts can sign in"
redirectUri: "https://app.example.com/signin-done.html",
},
});
const ready = msalApp.initialize();
document.getElementById("signin").addEventListener("click", async () => {
try {
await ready;
const nonce = await PrefsDB.idTokenNonce(); // a new code for each attempt
const result = await msalApp.loginPopup({ scopes: ["openid", "profile"], nonce });
const db = await PrefsDB.getkeyWithIdToken(result.idToken, { provider: "microsoft", name: "settings" });
await db.key("theme").write("dark");
console.log(await db.key("theme").read());
} catch (err) {
console.error("Sign-in failed:", err.error || err.errorCode, err.message);
}
});
</script>
# 1. A one-time code, to pass to Microsoft as the nonce
curl -s https://prefsdb.com/api/v1/getkey/nonce/
# 2. The user signs in with Microsoft in a browser. Microsoft returns an
# ID token containing the code; that can't be done with curl.
# 3. Trade the ID token for the user's key (in the request body, never the URL)
curl -s -c cookies.txt https://prefsdb.com/api/v1/getkey/ \
--data-urlencode "id_token=$ID_TOKEN" \
--data-urlencode "provider=microsoft" \
--data-urlencode "name=settings"
A few things to know:
- Each code works once, within 10 minutes, so get a new one for every sign-in, as the example does.
- Popups need a click. Browsers allow a popup only right after one. The example waits for the one-time code first, which is normally quick. If your users see the popup blocked, fetch the code before they click (it stays good for 10 minutes).
namepicks one of several keys for the same user, as withgetkey(). Leave it out and it's"default".- The same options as
getkey()work here too:offline,offlineTtl,sessionTtl,optimistic,encryptionandthrowOnError.namespaceandappcreddon't apply. - To change the key itself, call
db.rotate()with no arguments.
Signing out
When your user signs out, call await db.logout(). It deletes what the key kept in this browser (cached values and changes not sent yet), so the next person on a shared computer can't see them. Then forget your db object. With the sign-in buttons, call signin.signOut() instead, which does the same. See Signing out.
Which users get which key
A key belongs to one Microsoft account in your app: your application ID and the name you pass. Another app gives the same person a different key.
Email address
Microsoft doesn't confirm email addresses for PrefsDB the way Google does (a work account's address is whatever its organization set). So PrefsDB doesn't keep an email address for these keys. That doesn't stop anything working: the key works right away, with no email step.
Letting users see their data
db.reviewUrl() is a page where your users sign in with Microsoft again to see their data, download it all, or upgrade their storage. It needs nothing from you, and it also works if your app is no longer around.
Microsoft's screen there shows PrefsDB as the app asking, not your app, since PrefsDB signs the user in with its own registration. Some organizations only let their members sign in to apps an administrator has approved; a work or school user there may need their administrator to allow PrefsDB first.
Storage
A signed-in user's free storage is shared across every app they use with PrefsDB through the same Microsoft account. See Storage space, and use db.onStorage() to warn users before they run out.
Encrypting data in the browser
Client-side encryption works with signed-in users too, but it still needs its own key or passphrase. Don't make one from anything in the Microsoft sign-in, such as the user's ID: PrefsDB sees it, so data encrypted with it wouldn't be private from PrefsDB.
If something goes wrong
| What you see | What to do |
|---|---|
IDTOKEN_INVALID |
The sign-in couldn't be checked, or it was too old. Ask the user to sign in again (with a new idTokenNonce()). |
IDTOKEN_REPLAYED |
That sign-in was already used. Get a new nonce and sign in again. |
IDTOKEN_KEYS_UNAVAILABLE |
Sign-in is briefly unavailable. Try again shortly. |
popup_window_error (from MSAL) |
The browser blocked the popup. See the note on popups above. |
More in Error Codes.