Skip to Content
Using the client

Authenticated requests

A fetch that sends the access token to one API, refreshes on a 401, and never leaks the token.

createAuthFetch(auth, baseUrl) returns a fetch for one API. It's built so that a token can't leak and a user can't be signed out by accident:

When…authFetch…
The path is on another originRejects with INVALID_OPTIONS. The token goes only to baseUrl's origin.
The response is a redirectRejects rather than following it.
The response is a 401Refreshes once, then sends a GET or HEAD again with the new token.
A POST, PUT, PATCH or DELETE gets a 401Refreshes, and resolves the 401. It never sends a request twice on its own.
The replayed request gets a 401 tooSigns out, unless signOutOnRepeated401 is false.
The session changes during the requestRejects with SESSION_CHANGED rather than resolve another account's answer.
Nobody is signed inRejects with UNAUTHENTICATED, unless optional is true.
The network failsRejects as fetch does, unchanged.

Because a write is never replayed for you, retry it yourself where sending it twice is safe. By then the token has been refreshed:

src/add-to-cart.ts
import {  } from "./api.js";

export async function (: number, : number) {
  const  = () =>
    ("auth/carts/add", {
      : "POST",
      : { "Content-Type": "application/json" },
      : .({
        ,
        : [{ : , : 1 }],
      }),
    });

  let  = await ();
  // The 401 refreshed the token, so one more try uses the new one.
  if (. === 401)  = await ();
  if (!.) throw new (`Add to cart failed (${.})`);
}

Two options change the defaults:

src/public-api.ts
import {  } from "@monarcode/session-kit/http";

import {  } from "./auth.js";
import {  } from "./backend.js";

export const  = (, `${}/`, {
  // One `fetch` for public and private endpoints: signed out, requests are
  // sent without a token instead of rejecting.
  : true,
  // For APIs that answer 401 for reasons other than a rejected token, so one
  // of those endpoints can't sign users out.
  : false,
});