Skip to content

Sign in with Google

Instead of asking your users for a name and seed phrase, you can let them sign in with their Google account. PrefsDB gives each user 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 Google client ID, the one you'd use for "Sign in with Google" anyway.
  • Your app, your sign-in screen. Google's consent screen shows your app's name, not PrefsDB's.
  • No email to confirm. Google has already confirmed the address, so the key works right away.
  • 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

There's no seed phrase in this flow. Instead:

  1. Your page asks PrefsDB for a one-time code (PrefsDB.idTokenNonce()).
  2. Your page shows Google's "Sign in with Google" button, set up with your Google client ID and that code.
  3. The user signs in on Google's own screens. Google hands your page a signed proof of who they are, which includes the code.
  4. Your page passes that proof to PrefsDB.getkeyWithIdToken() in place of getkey(name, seed). PrefsDB checks it with Google's keys and gives you the user's key.

From there it's an ordinary PrefsDB object: db.key("theme").write("dark") and everything else work as usual.

1. Get a Google client ID

If your app already has "Sign in with Google", use its client ID and skip this step.

  1. Open the Google Cloud console and create or pick a project.
  2. Set up the OAuth consent screen (on newer accounts, Google Auth Platform → Branding): your app's name, a support email and your logo. This is what your users see when they sign in.
  3. Go to APIs & Services → Credentials → Create credentials → OAuth client ID (or Google Auth Platform → Clients → Create client), and choose Web application.
  4. Under Authorized JavaScript origins, add the address your app runs at, such as https://app.example.com. Add each address you serve the app from: staging, a second domain, and so on.
  5. Save, and copy the Client ID. It looks like 1234567890-abc123.apps.googleusercontent.com. It isn't a secret; it goes in your page.

You don't need a client secret or a redirect address for this.

Your page must be served over https, or from http://localhost while you develop (add that address to the client's Authorized JavaScript origins too). PrefsDB refuses to sign in from a plain http page anywhere else.

2. Add the button to your page

<script src="https://accounts.google.com/gsi/client" async></script>
<script src="https://prefsdb.com/prefsdb.v1.min.js"></script>

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

<script>
const GOOGLE_CLIENT_ID = "1234567890-abc123.apps.googleusercontent.com";

// Google's button, set up with a fresh one-time code from PrefsDB.
async function showSignIn() {
  const nonce = await PrefsDB.idTokenNonce();
  google.accounts.id.initialize({
    client_id: GOOGLE_CLIENT_ID,
    nonce,
    callback: signedIn,
  });
  google.accounts.id.renderButton(document.getElementById("signin"), { theme: "outline", size: "large" });
}

// Google calls this when the user has signed in.
async function signedIn({ credential }) {
  try {
    const db = await PrefsDB.getkeyWithIdToken(credential, { name: "settings" });
    document.getElementById("signin").hidden = true;
    await db.key("theme").write("dark");
    console.log(await db.key("theme").read());
  } catch (err) {
    console.error("Sign-in failed:", err.error, err.message);
    showSignIn(); // a new code, so the user can try again
  }
}

window.addEventListener("load", showSignIn);
</script>
# 1. A one-time code, to pass to Google as the nonce
curl -s https://prefsdb.com/api/v1/getkey/nonce/
# -> {"status":"success","success":true,"nonce":"<NONCE>","expires":1792420000,...}

# 2. The user signs in with Google in a browser. Google returns an
#    ID token containing <NONCE>; 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=google" \
  --data-urlencode "name=settings"
# -> {"status":"success","success":true,"token":"<KEY>","message":"New key generated.",...}

A few things to know:

  • Each code works once, within 10 minutes. The example gets a new one whenever a sign-in fails, so the user can just click again. If your page stays open a long time before people sign in, call showSignIn() again every few minutes.
  • name picks one of several keys for the same user, as with getkey(). Leave it out and it's "default".
  • The same options as getkey() work here too: offline, offlineTtl, sessionTtl, optimistic, encryption and throwOnError. namespace and appcred don't apply.
  • Signing in again on any device, or after clearing the browser, returns the same key and data.
  • Keep the rest of your code as it is. After sign-in, db works exactly like one from getkey(). 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 Google account in your app: your Google client ID and the name you pass. Another app using PrefsDB gives the same person a different key, so apps never see each other's data.

Letting users see their data

db.reviewUrl() is a page where your users sign in with Google again to see their data, download it all, or upgrade their storage. Unlike the rest of the sign-in, this page shows PrefsDB's name, since it's where PrefsDB talks to them directly. It also works if your app is no longer around.

Storage

A signed-in user's free storage is shared across every app they use with PrefsDB. 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 Google sign-in, such as the user's ID or email: PrefsDB sees those, so data encrypted with them 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_EMAIL_UNVERIFIED The Google account's email address isn't confirmed.
IDTOKEN_KEYS_UNAVAILABLE Sign-in is briefly unavailable. Try again shortly.

More in Error Codes.