Skip to content

JavaScript

Browser · fetch

Getting a token silently in the browser

Use this in a frontend that should authenticate as one of your devices without any login UI — the device's client certificate, once installed in the OS/browser keychain, proves its identity during the TLS handshake for the /auth/token request itself.

browser_get_token.js
/**
 * Drop this into any other project's frontend to get an Obsidian access
 * token silently, then call your own API with it.
 *
 * Requires the device's client certificate to already be installed in the
 * OS/browser keychain (see README "Installing a device certificate").
 *
 * Caveat — browsers show a certificate-picker dialog the first time a site
 * requests a client cert (there is no JS API to suppress it). It is
 * per-browser-profile and one-time until the cert is deleted or the profile
 * is reset — not a per-request prompt. On managed devices you can pre-select
 * it automatically via the browser's AutoSelectCertificateForUrls enterprise
 * policy; see the README for the exact policy JSON.
 */

const OBSIDIAN_ISSUER = "https://auth.jyjwong.com"; // set to your Obsidian deployment

async function getAccessToken() {
  const response = await fetch(`${OBSIDIAN_ISSUER}/auth/token`, {
    method: "POST",
  });
  if (!response.ok) {
    throw new Error(`Obsidian token request failed: ${response.status}`);
  }
  const { access_token, expires_in } = await response.json();
  return { access_token, expires_in };
}

async function callProtectedApi() {
  const { access_token } = await getAccessToken();

  const response = await fetch("https://api.jyjwong.com/reports", {
    headers: { Authorization: `Bearer ${access_token}` },
  });
  return response.json();
}

Call getAccessToken() before hitting your own API, then attach the token as a normal Authorization: Bearer header — exactly like the callProtectedApi() helper above does.

The certificate picker is one-time, not per-request

The first time a browser profile visits a site that requests a client certificate, it shows a picker dialog — there's no JS API to suppress it. It's per browser profile, not per request: once selected, it's remembered until the certificate is removed or the profile is reset.

On a device you manage yourself, some browsers support pre-selecting the certificate for a given origin via an enterprise policy (Chrome's AutoSelectCertificateForUrls), removing the picker entirely. See the repository README for the exact policy JSON — it's a convenience, not a requirement.

Prerequisite: installing the device certificate

This snippet assumes the browser already has a client certificate for this device installed. That's a one-time, per-device setup step — bundling the key + cert into a .p12 file and importing it into the OS/browser keychain — covered in the README's "Installing a device certificate" section. It isn't part of the frontend code itself, so it isn't duplicated here.