Enlitt

Personal login and business credentials

Personal login is mandatory for every managed call. Business credentials never leave the server.

Enlitt draws one hard line through every piece of authentication in this SDK: personal authentication is what a browser is allowed to see and carry, and a business credential never is.

Personal login is mandatory

Every managed call — standard or premium — is made on behalf of one logged-in Enlitt user. There is no anonymous or application-attributed call: enlitt() resolves the user from an ambient session, and if none resolves, the call fails with EnlittLoginRequiredError (personal_login_required) before any provider is ever reached. This applies identically to both routes:

"It belongs to both the standard and premium paths identically, with the provider left uninvoked either way: the alternative — letting premium proceed at the business's own cost — would mean every user whose session expired silently moved their spending onto the business."

In other words, a premium call made with no personal session fails exactly like a standard one — same code, same uninvoked provider, same refusal before any network request to a model. There is no code path in which a missing personal session costs the business anything.

  • Mint end@enlitt/sdk/server's callback handlers (createLoginStartHandler, createCallbackHandler, createLogoutHandler) redirect the user to Enlitt's own login, receive a one-time code at the application's registered redirect URI, exchange it for an opaque session token — authenticated with the business's own secret key — and set that token as an HttpOnly, Secure, SameSite=Lax cookie (enlitt_session by default) on the business's own domain. The token, and the one-time code that produced it, are never written into a URL, a redirect target, a log line, or an error body.
  • Read end@enlitt/sdk/server's enlittSessionMiddleware() reads that same cookie on later requests and makes it available through an AsyncLocalStorage context, which enlitt() reads automatically. A caller that cannot rely on that ambient context — a background job, a queue worker, a call made for a linked account outside any HTTP request — constructs an explicit EnlittSession with enlittSession(token) and passes it as enlitt(target, { session }) instead.

The token itself is opaque end to end: nothing in the SDK reads, parses, or validates what it contains, and nothing about a user's identity, balance, or plan is ever visible to the business through it. Enlitt is the only party that resolves a token to a user.

Business credentials are server-only

A business secret key (ENLITT_SECRET_KEY, or EnlittOptions.secretKey / CallbackConfig.secretKey) authenticates the business, never a personal user, and is resolved through exactly one function: resolveBusinessAuthorizationHeader(). That function:

  • throws EnlittConfigurationError immediately if it is ever evaluated in a browser environment (detected by the simultaneous presence of window and document), before it reads any secret;
  • throws the same error for a missing or unusable secret (one containing a control character, a space, or a newline — unusable rather than merely unusual, since a pasted trailing newline could otherwise split the header);
  • never logs, serializes into a thrown error, or returns the secret to a caller.

@enlitt/sdk/server is excluded from browser bundles by its own package exports condition; the runtime check above is the second, independent net for a bundler that ignores that condition.

Never place a business secret key, or any code that imports @enlitt/sdk/server, in code shipped to a browser. If your framework renders a component on both server and client, keep every enlitt() call, every callback handler, and every business.info() call in a server-only module (a Server Component, a Server Action, a route handler, or an equivalent your framework does not bundle for the client).

What is browser-safe

Nothing described on this page issues a client-visible credential of its own: the session cookie is HttpOnly (unreadable from client JavaScript by design), and the only thing the browser ever holds is that cookie plus whatever your own UI renders from a server-fetched read model. There is no separate "publishable" or client-side Enlitt key in v1.

On this page