Skip to content

Sign-in Buttons

Add "Sign in with Google", "Sign in with Apple", "Sign in with Microsoft" and "Sign in with GitHub" buttons to your page with a few lines. Each user who signs in gets their own key, the same one every time, on any device.

The buttons are each provider's own: Google's and Apple's are drawn by Google's and Apple's scripts, and the Microsoft and GitHub buttons follow those companies' design rules. The add-on also takes care of the fiddly parts of sign-in: loading each provider's script, the one-time codes, and getting popups past the browser's popup blocker.

You can start from the ready-made sign-in page instead.

Before you start

Set up each provider you want, as described on its own page. GitHub needs no setup.

Provider What you need Setup
Google A client ID Sign in with Google
Apple A Services ID, and one of its Return URLs Sign in with Apple
Microsoft An Application (client) ID, and a return page on your site Sign in with Microsoft
GitHub Nothing Sign in with GitHub

For Microsoft, the return page is an empty page on your site that Microsoft's sign-in window comes back to. Use signin-done.html and register its address as a Single-page application redirect URI.

Your page must be served over https, or from http://localhost while you develop (except for Apple, which needs a real https address).

Add the buttons

<div id="signin"></div>

<script src="https://prefsdb.com/prefsdb.v1.min.js"></script>
<script src="https://prefsdb.com/prefsdb.signin.v1.min.js"></script>
<script>
const signin = PrefsDB.signIn({
  name: "settings",
  google:    { clientId: "1234567890-abc.apps.googleusercontent.com" },
  apple:     { clientId: "com.example.web", redirectUri: "https://app.example.com/" },
  microsoft: { clientId: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
               redirectUri: "https://app.example.com/signin-done.html" },
  github: true,

  onSignIn: async (db, { provider }) => {
    // db is ready to use, like the result of getkey()
    await db.key("theme").write("dark");
    console.log("Signed in with", provider, await db.key("theme").read());
  },
  onError: (err) => {
    if (err.error !== "POPUP_CLOSED") console.error(err.error, err.message);
  },
});
signin.mount("#signin");
</script>
# The buttons run in the browser. For the HTTP calls behind a sign-in
# (a one-time code, then trading the provider's token for a key), see
# the cURL examples on each provider's page.
curl -s https://prefsdb.com/api/v1/getkey/nonce/

Leave out the providers you don't use. The buttons appear one under the other, in the order Google, Apple, Microsoft, GitHub (change it with order).

The add-on loads each provider's script only when that provider is in your list.

Start from a template

signin-template.html is a complete sign-in page: a card with the buttons, a "Signing in…" message, friendly error messages, a "Last used" label on the button the user picked last time, and a signed-in view with a link to the user's data and a sign-out button. It follows the light or dark setting of the user's device.

  1. Download signin-template.html, and signin-done.html if you use Microsoft.
  2. Fill in CONFIG at the top of the script: your IDs, and delete the providers you don't use.
  3. Put the files on your site.
  4. Replace showApp() with your app.

Options

Option What it does
google { clientId }. Add oneTap: true to also show Google's One Tap prompt, and button to change Google's button (Google's renderButton options, such as { shape: "pill" }).
apple { clientId, redirectUri }: your Services ID and one of its Return URLs. Optional: locale (such as "fr_FR", for the button's language), scope (default "email"; "" to not ask for an email address), button (Apple's button settings, such as { type: "continue" }).
microsoft { clientId, redirectUri }: your Application (client) ID and your return page. Optional: authority (default "https://login.microsoftonline.com/common"; it must match the account types your registration allows, see Which accounts can sign in), button ({ theme: "dark" }, { label: "…" }), msalUrl (your own copy of Microsoft's MSAL.js).
github true, or { button: { theme, label } }.
name Which of the user's keys to use, as with getkey(). Default "default".
offline, offlineTtl, sessionTtl, optimistic, encryption, timeout, throwOnError, remember The same as for getkey(). With remember, PrefsDB.resume(name) gets the key back after a reload (see Staying Signed In).
theme "light" (default) or "dark": the background the buttons sit on.
width Button width in pixels, default 280. Google's button is 200–400 wide and Apple's 130–375.
order Which buttons mount() shows, in order, such as ["apple", "google"]. A provider you leave out can still use your own button.
onSignIn(db, { provider, previousProvider }) Called with a ready-to-use PrefsDB object after a sign-in. previousProvider is set when this browser last signed in with a different provider, which means a different key.
onError(err) Called when a sign-in doesn't work. See below.
onStart({ provider }) Called when a sign-in begins, for showing "Signing in…".

The object PrefsDB.signIn() returns also has:

  • mount(element) puts the buttons into an element (or a selector such as "#signin").
  • signOut() signs the user out: it calls db.logout() on the PrefsDB object the last sign-in gave you, which deletes what that key kept in this browser (cached values and changes not sent yet), and keeps Google from signing the user straight back in. Call it (and await it) when your user signs out. signOut({ keepLocal: true }) keeps the browser's copy. See Signing out.
  • destroy() removes the buttons.
  • lastProvider() returns the provider this browser signed in with last time.

Using your own button

Microsoft and GitHub have no official ready-made button, so you can use your own element for them:

signin.attach(document.getElementById("my-github-button"), "github");
# Not applicable: buttons run in the browser.

Google and Apple sign in only through their own buttons, so use mount() for them.

If something goes wrong

onError gets an object like { error, message, provider }, the same for every provider:

error What it means
POPUP_CLOSED The user closed the sign-in window. Usually nothing to show.
POPUP_BLOCKED The browser blocked the sign-in window. Ask the user to allow pop-ups for your site.
NOT_READY The user clicked before sign-in was ready, for example while offline. Trying again usually works.
SCRIPT_LOAD_FAILED A provider's script couldn't be loaded (offline, a blocker, or your site's Content-Security-Policy). That provider's button is left out.
SIGNIN_FAILED The provider reported a problem; message has its details.
IDTOKEN_INVALID, … PrefsDB's own errors, as listed in Error Codes.

Good to know

  • Each way in is a separate key. The same person signing in with Google one day and GitHub the next (or with a seed and email) gets two different keys, each with its own data. They aren't linked. Tell your users which one to use, and use the hint the add-on gives you: when this browser last signed in with a different provider, onSignIn gets it as previousProvider, so you can say "You signed in with GitHub last time. This is a different account." The button they used last is also marked "Last used".
  • One set of buttons per page. Google's and Apple's scripts each keep one setup per page. To change the buttons, call destroy() and create new ones.
  • Content-Security-Policy. If your site sends one, allow the scripts the add-on loads: https://prefsdb.com and, for the providers you use, https://accounts.google.com/gsi/client, https://appleid.cdn-apple.com and https://cdn.jsdelivr.net (Microsoft's MSAL.js). Google also needs https://accounts.google.com/gsi/ under frame-src and connect-src and https://accounts.google.com/gsi/style under style-src; Microsoft needs https://login.microsoftonline.com under connect-src. Apple's button is drawn with inline styles, so with Apple style-src also needs 'unsafe-inline'.
  • Already using MSAL.js? If your page has loaded it already, the add-on uses that copy.
  • Pop-ups. Sign-in windows open straight from the click, which browsers allow. A page that sends Cross-Origin-Opener-Policy: same-origin cuts the window off from the page; use same-origin-allow-popups.