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.
The session cookie and its two ends
- 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 anHttpOnly,Secure,SameSite=Laxcookie (enlitt_sessionby 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'senlittSessionMiddleware()reads that same cookie on later requests and makes it available through anAsyncLocalStoragecontext, whichenlitt()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 explicitEnlittSessionwithenlittSession(token)and passes it asenlitt(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
EnlittConfigurationErrorimmediately if it is ever evaluated in a browser environment (detected by the simultaneous presence ofwindowanddocument), 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.