Skip to content

Yielded Auth

Authentication that fits your Effect application.

Schema for the contract. Layers for your backend. Effect Atom for the client. Passwords, passkeys, codes, and OAuth with your accounts, your database, and your policies.

Get startedSee how it fits
bun add @yielded/auth@beta

Describe your session claims and the actions clients may call with Effect Schema. The server, HTTP routes, and client share that definition.

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) }),
});
  • Server handleryield* auth.signIn({ email, password })
  • HTTP routePOST /auth/signIn
  • Client Effectyield* client.auth.signIn({ email, password })
  • Reactconst [result, signIn] = useAtom(auth.signIn)

Inputs and public results use the same schemas. Expected failures stay typed; credentials travel through the private HTTP boundary. Clients reach only the actions you declare.

Choose your methods and session behavior, then supply their dependencies with Layers. Inside a handler, yield* AppAuth gives you auth alongside your other application services.

apps/server/auth.ts
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" });

Provide storage, account policy, hashing, and keys to AuthRoutes; its Layer type shows what is still needed. Your app owns account creation and authorization. See how Auth fits into Effect, or add it to an existing HttpApi.

Derive an Effect HttpClient service and atoms from the shared contract:

apps/web/auth-client.ts
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);

Read auth.session and dispatch auth.signIn or auth.signOut with ordinary @effect/atom-react hooks. Auth mutations refresh auth queries automatically. Compose workflows in Effect and connect your application’s queries through reactivity keys. Build the client.

Keep your customer or employee model. Use managed auth tables, map your own SQL schema, or supply storage services for a different backend. Changing storage Layers keeps the contract and client intact.

Who owns each layer of the auth stack at each storage level
Managed tablesPersistence.managed(…)Your schemaPersistence.map(…)Your servicesLayer.mergeAll(…)
Account tableYouYour table and IDs, mapped by column.YouYour table and IDs, mapped by column.YouYour records and IDs, in any store.
Auth tables and migrationsYielded AuthDefined for you. Drizzle Kit generates migrations you review.YouYour table names, columns, and migrations.YouYour durable store; SQL is optional.
Queries and transactionsYielded AuthRun for you.Yielded AuthRun against your tables, checked at startup.YouYour implementation of each storage service.
Sign-in workflowsYielded AuthRun for you.Yielded AuthRun for you.Yielded AuthRun for you, on your storage.
Contract and clientUnchangedThe same AuthApi, AppAuth, and client at every level. Only Layers change.
Runnable appManaged DrizzleCustom Drizzle, Effect SQLCustom services
  1. Managed tables

    Persistence.managed(…)
    Account table
    You
    Your table and IDs, mapped by column.
    Auth tables and migrations
    Yielded Auth
    Defined for you. Drizzle Kit generates migrations you review.
    Queries and transactions
    Yielded Auth
    Run for you.
    Sign-in workflows
    Yielded Auth
    Run for you.

    Managed Drizzle

  2. Your schema

    Persistence.map(…)
    Account table
    You
    Your table and IDs, mapped by column.
    Auth tables and migrations
    You
    Your table names, columns, and migrations.
    Queries and transactions
    Yielded Auth
    Run against your tables, checked at startup.
    Sign-in workflows
    Yielded Auth
    Run for you.

    Custom Drizzle, Effect SQL

  3. Your services

    Layer.mergeAll(…)
    Account table
    You
    Your records and IDs, in any store.
    Auth tables and migrations
    You
    Your durable store; SQL is optional.
    Queries and transactions
    You
    Your implementation of each storage service.
    Sign-in workflows
    Yielded Auth
    Run for you, on your storage.

    Custom services

  4. Contract and client

    UnchangedThe same AuthApi, AppAuth, and client at every level. Only Layers change.

The database and backend guide explains the choices and the durability each implementation must provide. Four runnable account apps show the same workflows across Drizzle, Effect SQL, and a non-SQL store.

Method What you can build
Passwords Registration, sign-in, and recovery.
Passkeys WebAuthn sign-in and credential management.
Email codes & magic links Passwordless sign-in and address verification.
Phone codes SMS sign-in and number verification.
Two-factor authentication Authenticator apps after a first factor.
OAuth & OIDC Provider sign-in, account linking, and retained API access.

Each guide shows the strategy, the services you supply, and the calls you make. Start with GitHub or Google for provider setup.