Skip to content

[Feature Request] localStorage for storing keystatic-gh-access-token cookie #1550

Description

@adhitht

Summary

keystatic-gh-access-token is stored in a non-HttpOnly cookie because the browser reads it directly when making GitHub API calls. The problem is that some enterprise firewalls (Fortinet being a common one) automatically add HttpOnly to all cookies going outside of the network, which breaks the Keystatic admin UI since JavaScript can no longer access the token.

Problem

The token is set like this:

[
'Set-Cookie',
cookie.serialize('keystatic-gh-access-token', tokenData.access_token, {
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
maxAge: tokenData.expires_in,
expires: new Date(Date.now() + tokenData.expires_in * 1000),
path: '/',
}),
],

The token is read like this:
const cookies = parse(document.cookie);
const accessToken = cookies['keystatic-gh-access-token'];

httpOnly is intentionally left out so the frontend can read the token and authenticate GitHub API requests. But behind certain network firewalls, that choice gets overridden, the cookie gets HttpOnly stamped onto it, and things break. There's no workaround available to the application once that happens.

Solutions

Option 1: localStorage fallback (opt-in flag)

Add a config flag in keystatic.config.ts under storage if kind is github that switches token storage from a cookie to localStorage, similar to how Keystatic Cloud auth already works (localStorage.getItem('keystatic-cloud-access-token')). Users in restricted environments could opt into this, leaving the default behavior unchanged.

For Example:

{
    "storage": {
        "kind": "github",
        "repo": "thinkmill/keystatic",
        "useLocalStorageForAccessToken": true 
    }
}

Option 2: Server-side GitHub proxy (preferred)

Route GitHub API requests through Keystatic's existing API routes instead of making them directly from the browser:

Browser → Keystatic API → GitHub API

The browser never touches the token, so keystatic-gh-access-token can be HttpOnly (or dropped from the client entirely). This also closes off client-side token exposure as a side benefit.

Contribution

If the issue looks good to you, I can work on this one.

PS: useLocalStorageForAccessToken might be a bad variable name, open to suggestions :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions