Passwordless Authentication
Sign in with WebAuthn passkeys or a 6-digit email code. Offer passwordless login with a fallback for users who do not yet have a passkey.
An open-source, OpenID Certified™ Identity & Access Platform for Cloudflare Workers — authentication, authorization, and federation on an edge-first architecture.
Pre-1.0. Core protocols are implemented; production hardening and validation are ongoing.
Sign in with WebAuthn passkeys or a 6-digit email code. Offer passwordless login with a fallback for users who do not yet have a passkey.
Connect applications and existing identity providers through OpenID Connect and SAML 2.0. Create accounts at first login and link external identities.
Control access through roles (RBAC), attributes (ABAC), and relationships (ReBAC). Check permissions through an API, with policies scoped to each tenant.
Automatically expand Cloudflare D1 capacity as your user base grows. Forecast demand and add database shards so you can grow without switching platforms.
Product notes
Separate personal data to support investigation and deletion.
Product notes
This design began with an uncomfortable moment in everyday operations: investigating a failed login and seeing information you did not need to see.
Run an identity platform and this arrives regularly: "one of our users can't sign in." To diagnose it, you enter the customer's environment and find the account.
What you need is narrow. Is it locked. When did the last attempt fail, and where. Which route did they come through. Is the passkey registration still valid.
None of that involves who the person is. Open the account anyway and their name is there. Their email. Their phone number. Their linked account handles, all on the same screen. You needed state. You got a person.
"Please don't look" is not a control
while it is rendered on the page.
And nothing here went wrong. The customer asked. You followed procedure. You did the work. You still saw it. The structure put it in front of you.
Solve that with policy and training and you have built a control that depends on an engineer's memory and conscience. Depend on that long enough and it becomes an incident. Separating personal data into its own database started as an attempt to solve this one thing structurally.
Identifying data sits in a physically separate database. Not retrofitted — the repository layer is split at the source.
Split this way, the opening problem dissolves. Lock state, failed attempts, device information — all of it is on the left. You can grant the access an investigation needs without granting the right side. Nobody has to remember to look away.
The same structure answers audit questions as a side effect. "Where do names and email addresses live" has a one-line answer, and deletion scope can be shown as a range. Solving the operational problem produced the explainability — in that order.
Worth stating bluntly, because the misreading is dangerous. This split is not a legal boundary between personal and non-personal data.
Core DB holds IP addresses, device information, session history, authentication events, credential metadata and stable internal user IDs. Depending on context, those are personal data too. Individually they may not identify anyone; combined with other information, they can.
What Authrim actually separates is directly identifying data from operational identity data. The goal is that an investigation can run on the second without touching the first — not that the second needs no protection.
So never say "personal data only exists in the PII DB." Say: "directly identifying data such as names and email addresses is isolated in the PII DB, and investigation access can be granted without reaching it."
"Delete my account" is trivial to execute. The two requests that follow are not.
One is proving the deletion — when, by whom, and why, recoverable later. The other is blocking re-registration for a retention window, which is a common business rule.
Which is a contradiction. Both need you to recognise a person you supposedly erased. Keep anything that identifies them and you did not erase them.
The implementation states its own reasoning: store no PII, keep only the fingerprint needed to prevent duplicates, expire after the retention window, and record who deleted, when, and why.
One note for engineers. Email addresses are low-entropy. Fingerprint them with a plain hash and a dictionary attack recovers the original. "Not recoverable" is not unconditional.
Authrim uses an HMAC-SHA256 blind index with a secret key, carrying a key-generation number so keys can be rotated. Without the key, brute-forcing the fingerprint is not available.
Which means key isolation is the precondition for the guarantee. Store the key beside the fingerprints and the guarantee is gone. Do not drop that condition when describing this externally.
Return to the failed-login report. The investigator needs to find where authentication stopped. They usually do not need to open a name or phone number.
Authrim separates directly identifying information so that troubleshooting access can be granted without access to that store. When an investigation does need personal information, someone with the appropriate additional permissions handles it.
Encryption and access control protect the data; audit logs record its use. Alongside those measures, an investigator should be able to finish routine work without opening personal information they do not need. Separating storage makes that the starting point for everyday operations.
Implementation. Complete — storage split and access boundary both in effect
Validation. Covered by automated tests in this repository
Operational maturity. Hardening in progress. Authrim is pre-1.0.
This design makes deletion workflows easier to run. It is not itself a statement of legal compliance. Actual conformance depends on your procedures and contracts. Keep that distinction in external material.
Why logout certification matters for both OP and RP.
Product notes
A person signs in once, but more than one session is created along the way. Logout depends on ending the relevant sessions across that entire path.
Say you add "Sign in with Google" to your service. To the user, that is one button press.
Underneath, every system on the path issues and stores its own session. Google holds one. Authrim holds one. Your app holds one. Three.
A surviving session may let the user keep working there, or sign in again without re-entering a password.
Logout is not printing "You have been signed out."
It means choosing the scope of logout and ending the sessions within that scope.
The "keys" here are sessions. Access tokens and refresh tokens are a different mechanism, and ending a session does not necessarily invalidate tokens already issued. Stopping a token requires revocation — a distinct operation.
In OIDC terms, session logout, token revocation and upstream account disablement are three different things. This installment covers only the session side. When a token stops working is covered in token introspection and revocation.
In this connection, the upstream provider provides login and your application requests it. Authrim's role flips depending on which way it faces.
Login flows downhill on its own. Logout does not travel unless someone carries it.
Ending an upstream session does not automatically remove sessions in Authrim or your application. Termination needs to be communicated downstream, and each receiver must end its matching session. The next diagram shows the chain when the required notification methods and configuration are in place.
| Situation | What a broken chain produces |
|---|---|
| Offboarding | HR revokes access. The laptop still has the app open, and internal data stays visible until morning. |
| Shared terminals | Retail, hospital, call center. The previous person signed out — then a second tab shows their dashboard. |
| Lost device | "Sign out everywhere" was pressed. Only the session in hand actually ended. |
| Incident response | You cut off the compromised user. The attacker's session runs to expiry anyway. |
| Audit | "Demonstrate that logout propagates to all systems." Nothing to show. |
None of these mean logout is missing. The button exists. The screen changes. The reach is narrower than anyone assumed — that is what makes it hard to catch.
There are two ways to tell downstream. One of them is breaking.
Authrim's certification covers receiving the bottom method. Receiving a notice and sending it onward each need to be checked.
Authrim acts as a relying party (RP) toward the upstream provider and an OpenID Provider (OP) toward applications. Carrying logout onward requires conformant behaviour in both roles.
OP and RP logout profile certifications provide evidence for these two roles. Authrim holds logout profile certifications on both sides through the OpenID Foundation's self-certification process, using its official conformance tests.
Certification means the submitted implementation version passed the conformance tests for the submitted profiles. It does not guarantee immediate termination of every session across a customer's applications and network.
The upstream provider and each application must support the required methods, with notification endpoints and session mappings configured. Disabling an upstream account does not necessarily trigger a logout notice. Delivery failures, retries and failure visibility also need to be checked in the deployed configuration.
See the OpenID Foundation's Certified OpenID Relying Parties & Logout Profiles listing for certified versions and profiles, and its certification process for the scope of certification.
After logout, where does a signed-in session remain?
That is the question when handing a shared terminal to someone else or ending a former employee's access. Authrim handles both receiving and sending notices to connect session termination between the upstream provider and applications. Certification provides evidence about that implementation; testing the connected systems establishes whether logout reaches the intended scope.
Connect LDAP and AD without storing passwords.
Product notes
Your passwords already live in Active Directory. How do you add modern login without copying password hashes or publishing an inbound connector endpoint?
Employee accounts are in Active Directory. So is the password policy, expiry, and the offboarding switch. It has been running for years.
You want passkeys on top. You want MFA rationalised. You want more SSO into SaaS. The goal is clear, and the first step always lands on the same question: where does password verification happen?
Some configurations sync password hashes to the cloud; others ask the internal directory to verify credentials. The useful questions are where credentials live, which side opens the connection, and who operates that route.
WordWarden keeps verification with LDAP/AD and lets you choose the route. Authrim Relay provides an outbound connection for organisations that do not want to publish a new inbound endpoint.
Authrim WordWarden is a directory connector. A small service you run next to your LDAP/AD, with one job: take a username and password, ask the directory, return the verdict.
Login UI, sessions, passkeys, email codes, federation output, audit correlation and identity mapping all stay on the Authrim side. WordWarden does verification only, next to the directory.
The direction of the connection changes the network configuration and the components you operate.
WordWarden supports three transports. What separates them is whether your network has to publish a listener.
For a new deployment that should not add inbound access, start by considering Relay. An existing publishing platform or tunnel can also be worth using. The following are deployment scenarios, not claims about customer deployments.
Consider a company running AD at its headquarters where each new public server requires a separate review, or a university that does not permit incoming connections to its campus LDAP network. WordWarden opens the connection to Authrim, so no new inbound port needs to be published on that network.
No new public endpoint or separate tunnel process is needed. Outbound WebSocket traffic must be allowed, and WordWarden's health and connection still need monitoring. Relay cannot serve a network that prohibits external communication altogether.
An organisation already publishing internal tools through Cloudflare Tunnel may have a team responsible for cloudflared updates and routing. WordWarden can fit those procedures without opening a new inbound port.
You configure the hostname and route that let requests from Authrim reach the connector, and maintain the tunnel. The internal host needs no direct inbound access, but requests arrive through a route on Cloudflare.
A company, university or research institution may already have an infrastructure team operating a DMZ and reverse proxy for external integrations. An HTTPS endpoint reachable from Authrim can use that team's existing certificate, access-log and monitoring procedures.
No separate tunnel or Relay connection needs to be maintained. In return, the organisation permits the inbound route and takes responsibility for protecting and maintaining the public endpoint. The published route is the connector's HTTPS interface, not the LDAP/AD port exposed directly to the internet.
Every method requires operating WordWarden where it can reach LDAP/AD. Being an academic institution does not determine the method; existing infrastructure and network policy do.
In relay mode, WordWarden connects to Authrim using WebSocket from inside your network. WebSocket keeps a communication connection open so that either side can send messages over it.
WordWarden keeps that connection open and waits. When someone logs in, Authrim uses the same connection to ask, "Please verify this user." WordWarden checks with the internal directory and sends back the result.
Think of making a phone call from inside the organisation and staying on the line: the other person can speak too. There is no need for a new incoming connection for each request.
In practice that means the directory side publishes no URL at all. This avoids managing a hostname, certificate and WAF for a new public endpoint. Outbound permission, WordWarden maintenance and connection monitoring are still needed.
The difference is which side starts the connection. With Direct HTTPS, the organisation provides an endpoint that Authrim can connect to. With Relay, WordWarden inside the organisation opens an encrypted WebSocket connection (wss) to Authrim's Relay.
A typical stateful firewall or NAT tracks connections initiated from inside and allows their return traffic. This lets WordWarden receive verification requests without publishing an inbound port or configuring port forwarding for new external connections to it.
This does not mean that no ports are used. A typical wss connection uses TCP port 443 at the destination. The organisation's firewall or proxy must allow outbound access to Relay and sustained WebSocket connections. Requests cannot arrive over that route while it is disconnected, so connection monitoring still matters.
Reducing endpoints for new external connections does not remove the verification requests arriving over the established connection. Peer authentication and request validation remain necessary.
Reference: The WebSocket Protocol (RFC 6455)
An outbound connection still needs authentication. Relay combines connector authentication with checks on the configured destination.
WordWarden authenticates with an HMAC response to a short-lived challenge, signing a string containing the challenge ID and nonce. It also checks that the tenant and connector IDs in the destination URL match its configuration.
HMAC is required in all three transports. Relay reduces inbound exposure; it does not remove the need for connector authentication or secret management.
Worth being exact here, because the loose version is wrong. It is not true that the password never leaves your network.
The user types it into a login screen, so it transits Authrim. The accurate claim is "Authrim and WordWarden do not store it" — not "it never leaves."
On success, Authrim receives the verdict plus the requested attributes intersected with the connector's local allowlist. The requesting side does not decide what it can pull; the directory side decides what it will release.
That direction matters. No change on the Authrim side alone can widen what leaves your network.
Positioned in one line: this integration exists for the transition.
Leave LDAP/AD as the password authority. Keep people signing in with the account they already have. Enroll passkeys underneath, progressively. Keep email code as the recovery path. From the user's side nothing breaks; the authentication method quietly changes out.
The documentation also states the prohibition plainly: do not export LDAP/AD password hashes into Authrim. Do that and the bridge becomes a credential copy.
Preparing for public beta. First target is v0.1.0-beta.1.
Intended for pilots — organisations that can run a small service near LDAP/AD and understand the directory, network, TLS and secret-management boundaries. It is not a managed directory service.
Requires Authrim 0.3.2 or later with Directory Authentication and Relay enabled. In the current beta, configuration changes need a process restart.
"Credentials out, or traffic in"
is not the only menu.
Verify next to the directory, and make the connection outbound-only. Satisfy both and you get modern login without copying password hashes and without publishing a listener inside your network.
And what sits on the far side is not continued password use — it is the move to passkeys. Directory integration is the footing that lets that migration proceed without stopping anyone from logging in.
Add D1 shards without moving existing accounts.
Product notes
More users are arriving. That is welcome news, but it raises a question: how long can the current database hold them? Authrim prepares new account storage before it is needed, so growth does not have to begin with a migration project.
Cloudflare D1, the database Authrim uses, has a size limit per database: 500 MB on the Free plan and 10 GB on the Paid plan. As users and their data grow, another place to store that data will eventually be needed.
Authrim is built to distribute accounts across multiple databases from the start, so reaching that point does not require moving every existing account. We call each of these storage units a shard.
Keep existing accounts where they are, and add destinations for new accounts.That is the basic approach to expanding account storage.
Tenant settings such as OAuth clients and policies, accounts and personal information, and the indexes that locate an account from an email address are stored separately in Authrim.
More users do not mean every database has to grow together. Account storage and lookup indexes have different record counts and growth rates. Capacity is added where it is needed.
A new account is assigned to one of the shards available to its tenant. Healthy shards with a lower ratio of allocated accounts to their target count are preferred.
The signal here is not disk utilization. It is how many more accounts can be accepted within the configured target. With a target of 100,000 accounts, for example, a remaining margin of 20,000 helps determine when to prepare the next destination.
When the available shards have little headroom left, a prepared spare is assigned. The same approach applies to shared shards used by several tenants and exclusive shards used by just one.
Shared tenants
Exclusive tenants
Shared and exclusive tenants
Once automatic provisioning is configured, an operator does not have to create a database, prepare its tables and connect a new registration destination every time registrations grow. Adding capacity does not require a migration plan for existing accounts each time, either.
The operator checks that provisioning is progressing, failures are visible, and usage and costs remain within expectations. Permission problems or service limits still need attention. With that division of work, Authrim prepares the next storage destination.
With 20,000 account slots remaining, a service adding 100 accounts a day has much more time to prepare than one adding 10,000 an hour.
Authrim therefore estimates future capacity from recent registration rates as well as current allocations. Both account storage and lookup indexes are forecast. A scheduled job runs every minute, and account forecasts are also updated after allocation.
Shards already being created count toward the estimate. If several processes notice the same shortage, they should not each create another unnecessary database.
When spares are not enough, Authrim creates D1 databases through Cloudflare's management API. It creates the tables, configures Worker access and distributes the new storage locations. A database becomes an allocation target after its read and write checks pass.
Automatic provisioning must be enabled, with separate API tokens configured for D1 and Workers. When automatic execution is unavailable, an operator continues the work through the setup tool.
Progress is persisted during creation. A temporary connection failure can be retried from that state. Missing permissions or resource limits need an operator to resolve the cause before work can resume.
If preparation falls behind and account slots run out, new registrations may need to retry. Preparing ahead is intended to reduce that wait.
Adding capacity and moving existing data are separate operations. Moving a tenant from a shared shard to an exclusive shard, for example, requires copying existing data as well as providing a new destination.
The operator decides whether to start that migration. After approval, Authrim handles synchronization, verification and cutover.
The supported placement change is currently from shared to exclusive. Moving back to shared storage and automatically redistributing existing accounts evenly are not implemented.
Deleting a retired shard also requires operator approval. Growth does not automatically trigger the movement or deletion of existing data.
In a July 2026 test with 200,000 accounts, Core used about 208 MB, PII about 238 MB and Lookup about 426 MB. Each was below 5% of the Paid plan's 10 GB per-database limit. Actual usage depends on the attributes and indexes stored.
The default target is 100,000 accounts per shard, leaving room to prepare the next one instead of filling a database to its physical limit.
Authrim is pre-1.0, and long-running production experience at large scale is still to come. Measuring storage for 200,000 test accounts is distinct from operating a service used daily by millions of people.
A small service does not need a large deployment on day one. It can start with a few shards and add destinations as registrations grow. Authrim includes the preparation and procedures needed to do that.
When users start arriving, planning a database move should not become the first job on the list. We want to reduce that work so more time can go into the service itself.
Storage measured on July 30, 2026 with 200,000 test accounts. MB uses decimal units. For D1 capacity limits, see the Cloudflare documentation.
K6 Cloud tests cover representative OIDC workloads; capacity depends on workload shape, Cloudflare plan limits, storage, and sharding.
Test reports →Authrim has no per-user vendor fee — infrastructure cost depends on requests, CPU time, storage, and logging. A rough Cloudflare-cost reference, not a production quote.
Based on Cloudflare Workers pricing with a multiplier for KV, Durable Objects, and D1 from observed Authrim usage patterns.
Note — Infrastructure only. Excludes compliance, monitoring, support, operations, security review, external databases, and large R2/archive usage. Actual cost varies by deployment profile.
TypeScript-first APIs, JavaScript SDKs, and a setup workflow for evaluating and developing edge identity deployments.
Self-hosted control with SAML, SCIM, audit logging, tenant boundaries, and storage / logging controls under active hardening.
Start on Cloudflare with no per-user Authrim fee, then scale based on measured request, CPU, storage, and logging behavior.
OpenID Certification
Basic OP · Implicit OP · Hybrid OP · Config OP · Dynamic OP · Form Post OP · 3rd Party-Init OP
RP-Initiated OP · Session OP · Front-Channel OP · Back-Channel OP
Basic RP · Config RP · Dynamic RP · Form Post RP
RP-Initiated RP · Back-Channel RP
Security Profile: private key + DPoP · OpenID Connect · Message Signing: JAR · Message Signing: JARM · Client Credentials: private key + DPoP
Security Profile: private key + DPoP · OpenID Connect · Message Signing: JAR · Message Signing: JARM
Poll: Private Key · Ping: Private Key
Evaluate an open-source identity platform for Cloudflare Workers. Core protocol capabilities are implemented; production hardening is still active.