effect-auth

HTTP Operations

Bind standard effect-auth workflows to an application-owned HTTP contract.

HTTP Operations sit between domain services and HttpApi. Each *HttpOperations service exposes endpoint-shaped functions with the built-in request, success, error, and requirement types, but without a fixed route or group.

A custom Cloudflare endpoint owns the boundary while the operation retains standard auth behavior
Operation retainsCustom endpoint owns
Standard workflow and domain orchestrationPath, method, group, decoding, and API layout
Operation-specific request security, including rate limiting where definedOrigin/CSRF behavior, caller guards, and additional app policy
Public error translation and continuation resultsCompatible success/error schemas and any request/result adaptation
Session issuance, rotation, revocation, and cookie consequencesWhich methods are exposed and the matching browser client contract

For password sign-in this preserves response-level account-existence concealment, continuation handling, unexpected-infrastructure-error hiding, and session commitment. After identity normalization and password-size validation, account-dependent lookup failures perform one provider-owned dummy password verification; an existing credential performs only its real verification. Malformed or unsupported identities, oversized passwords, and earlier guard rejection remain cheap. Network and storage work can still differ, so end-to-end request timing is not guaranteed to be identical.

Bind a method

An Alchemy-deployed auth Worker can expose the standard sign-in workflow at an application-owned route:

import {
  HttpLoginApprovalFinalizerCapability,
  HttpLoginApprovalStatusCapability,
  LoginNotificationReportCapability,
  PasswordEmailVerificationCapability,
  layerNoDeps as httpEndpointCapabilitiesLayerNoDeps,
} from "@effect-auth/core/HttpApi/HttpEndpointCapabilities";

const HttpEndpointCapabilitiesLayer = httpEndpointCapabilitiesLayerNoDeps({
  passwordEmailVerification: PasswordEmailVerificationCapability.Disabled(),
  loginNotificationReport: LoginNotificationReportCapability.Disabled(),
  loginApprovalStatus: HttpLoginApprovalStatusCapability.Disabled(),
  loginApprovalFinalizer: HttpLoginApprovalFinalizerCapability.Disabled(),
});

const AppPasswordGroupLive = HttpApiBuilder.group(
  AppAuthApi,
  "password",
  Effect.gen(function* (handlers) {
    const password = yield* PasswordHttpOperations;
    return handlers.handle("signIn", password.signIn);
  })
).pipe(
  Layer.provide(
    PasswordHttpOperationsLive.pipe(
      Layer.provide(AuthRateLimitStandardLive()),
      Layer.provide(HttpAuthenticationCapabilitiesLive),
      Layer.provide(HttpEndpointCapabilitiesLayer),
      Layer.provide(AppAuthServicesLive)
    )
  )
);

AppAuthServicesLive can contain D1 stores and Cloudflare runtime adapters supplied from Alchemy bindings. HttpAuthenticationCapabilitiesLive and HttpEndpointCapabilitiesLayer are application assemblies built with their focused layerNoDeps functions. The first selects one snapshotted request-IP source and explicit tagged bot-verifier, trusted-device-cookie, and login-risk choices; the second selects four explicit endpoint choices. PasswordHttpOperationsLive constructs the complete password service, including reset operations and dependencies, although this group binds only signIn: Layers assemble per feature, handlers expose per endpoint.

Captured and execution-time requirements

Maintained secured operation Layers explicitly capture AuthRateLimit and HttpAuthenticationCapabilities when constructed. Generic rate limits, OAuth protocol/device limits, passkey risk context, identity, TOTP/recovery, MFA, and step-up paths all derive request data from that same immutable metadata snapshot. Adding a capability or a different metadata policy later to request context does not alter an existing operations service.

AdminPermissionDefinitionHttpOperations is the important exception: its returned Effects retain execution-time requirements for permission administration, sessions, cookies, and mandatory app authorization. Its focused preset installs middleware for those requirements; a custom group must provide an equivalent trusted context. See the permission-definition API.

Standard group middleware does not travel with a function. In particular:

ConcernCustom binding action
Schema errorsAttach AuthSchemaErrorMiddleware or define another explicit public shape
Origin/CSRFConfigure the custom group/API boundary
Standard operation policyProvide it while constructing operations; do not execute it twice
Application authorizationCompose it around the operation
CORSConfigure response headers and preflight independently
Cache policyPreserve required headers such as OAuth no-store at the custom boundary

Catalog

AreaOperation service prefixes
Primary authenticationPassword, EmailAuth, EmailOtp, MagicLink, Passkey, EmailVerification
Sessions and assuranceSession, Mfa, StepUp, Totp, RecoveryCodes, LoginApproval, LoginNotification
Identity and securityIdentity, TrustedDevice, SecurityTimeline, AdminSession, AdminTrustedDevice, AdminSecurityTimeline, AdminPermissionDefinition
Tokens and federationOAuth, OAuthProviderAuthorization, OAuthDeviceAuthorization, OAuthDeviceApproval, OAuthToken, OAuthTokenIntrospection, OAuthTokenRevocation, ApiKey, RefreshToken, Jwt, JwtDiscovery, OidcDiscovery

Each prefix names PrefixHttpOperations and normally PrefixHttpOperationsLive; TypeScript exposes the exact methods and environment requirements from the owning public subpath.

OAuth device start and browser approval are separate services because they have different callers and policy boundaries. Token exchange, introspection, and revocation are separate too. The token operation dispatches through explicit OAuthTokenGrantRegistry registrations; it does not discover optional grants from ambient context. Operation methods do not carry the standard groups' no-store or origin middleware into a custom route.

If custom routes diverge from the standard client protocol, define the application contract explicitly. createAuthClient({ protocol }) and defineAuthHttpApiExtension can replace, remove, or add typed client operations; they cannot infer an arbitrary server API. Continue with Custom Auth API.

On this page