Documentation · Getting started · yielded.dev
Composable authentication, sessions, and identity workflows for Effect.
Define your contract with Schema, supply infrastructure with Layers, and call auth alongside your other Effects. The same contract connects your server to an Effect HttpClient service and Effect Atom queries and mutations.
Your application owns its accounts, identifiers, and authorization policy. Use managed auth tables, map an existing SQL schema, or implement storage services against another backend. The auth API stays the same when you change storage. Auth uses Effect and first-party crypto, JOSE, and OAuth packages. Applications select crypto Layers; optional companions supply database, WebAuthn, and platform integrations.
Start with Auth in an Effect application or compare database and backend choices. The four account apps show managed Drizzle, custom Drizzle, Effect SQL, and non-SQL persistence.
Install the beta release with Effect:
bun add @yielded/auth@beta effectPrefer named namespace imports from @yielded/auth. Direct module paths such as
@yielded/auth/AuthContract remain available; see the
import guide.
Define the shared contract in packages/domain/auth-contract.ts:
import { Schema } from "effect";
import { AuthContract } from "@yielded/auth";
export const AuthApi = AuthContract.make("app/Auth", {
claims: Schema.Struct({ displayName: Schema.String }),
actions: (sessions) => ({ signIn: AuthContract.passwordSignIn(sessions) }),
});Bind the server implementation and mount its HTTP routes:
import { Auth, Http, Password, Sessions } from "@yielded/auth";
import { AuthApi } from "@app/domain/auth-contract";
export const AppAuth = Auth.make(AuthApi, {
sessions: Sessions.stateful({ maxAge: "8 hours", idleTimeout: "30 minutes" }),
strategies: { password: Password.make() },
defaultStrategy: "password",
});
export const AuthRoutes = Http.layer(AppAuth, { origin: "https://app.example.com" });The eight-hour lifetime and thirty-minute idle timeout are application policy.
Supply your crypto, persistence, and account Layers to AuthRoutes, then merge it with
your router. For application routes that call auth, use the middleware shown in the
router composition.
Inside an existing Effect handler, call the service directly:
const auth = yield* AppAuth;
const result = yield* auth.signIn({ email, password });The request context supplies credentials and cookie delivery. auth.getSession(),
auth.requireSession(), and auth.signOut() use the same boundary. An
Authenticated sign-in result contains a session with typed claims.displayName.
Create the client and its atoms from the same contract:
import { Atom as AuthAtom, Client } from "@yielded/auth";
import { AuthApi } from "@app/domain/auth-contract";
export const AppClient = Client.make(AuthApi, { baseUrl: "https://app.example.com" });
export const auth = AuthAtom.make(AppClient);Use auth.session, auth.signIn, and auth.signOut with ordinary
@effect/atom-react hooks. Auth mutations refresh auth queries automatically;
React renders and dispatches. Compose your own queries through the same client:
import { Effect } from "effect";
import { AppClient, auth } from "./auth-client";
export const memberName = auth.runtime.atom(
Effect.gen(function* () {
const client = yield* AppClient;
const session = yield* client.auth.getSession();
return session?.claims.displayName ?? null;
}),
);Fetch is configured by default. To customize transport, compose AppClient.layer
with your HttpClient Layer and pass { layer: ClientLive } to AuthAtom.make. See the
client guide
for React, shared invalidation, and standalone Effect calls.
Add passwords, passkeys, email or phone codes, two-factor authentication, and OAuth through strategies and their required Layers. OAuth can also retain encrypted provider grants for calling APIs after sign-in.
Start with the documentation and
consumer examples. The public library lives in
packages/auth; examples are leaf workspaces.
Install Bun and Vite+, then run:
vp install
vp run patch:tsgo
vp run readyThe toolchain guide covers release setup and contributor rules. Shared versions live in the root catalog. Formatting, linting, strict TypeScript, package exports, dependency purity, tests, and builds use Vite+.
See third-party notices for open-source credits and licenses accompanying the reusable crypto and JOSE packages.