Amazon Cognito vs ClavionX: The Decisions You Make on Day One
Cognito makes some decisions permanent at pool creation and keeps the password hashes. Lambda trigger budgets, multi-Region replication, identity pools, and the exit test applied to both.
Creating an Amazon Cognito user pool takes about four minutes. The console asks how users sign in: username, email or phone. It asks which attributes are required. You probably add a couple of custom attributes, click through and have working authentication before your coffee cools.
About a year later, the product team wants phone number to be optional for a new market, rather than required as it was at launch. Someone else wants to rename custom:plan_type, because it now means something different. The answer to both is the same. You can't. Create a new user pool and migrate your users into it. Migrating them means passwords, and Cognito won't give you the password hashes.
None of this is hidden. It's in the documentation, and it follows from how Cognito is built. It's still the most consequential thing to understand about Cognito, and the best way into a comparison with ClavionX. Much of what separates identity platforms isn't what they can do. It's which decisions they make permanent, and when they ask you to make them.
Disclosure: I work on ClavionX. For many applications that live entirely in AWS, Cognito is a sensible choice, and this post says which. It also says where ClavionX has the same problem.
What Cognito actually is
Cognito is AWS's identity service, and it behaves like an AWS primitive. It's regional, API-first, configured through CloudFormation or CDK, billed by usage, and integrated with everything else in the account. It has two halves that are often confused:
- User pools: a user directory plus an OIDC and OAuth 2.0 authorization server. Here users sign up and sign in, federate from social or SAML and OIDC providers, and get JWTs.
- Identity pools: a broker that exchanges tokens from a user pool or another IdP for temporary AWS credentials from STS. That lets a mobile app upload straight to S3, or call an AWS API directly, with an IAM role scoped to that user.
In November 2024, user pools gained feature plans. Lite covers the original feature set. Essentials adds managed login, passkeys and passwordless, and access-token customization. Plus adds risk-based adaptive authentication and compromised-credential detection. In June 2026, Cognito added multi-Region replication for Essentials and Plus pools, more on that below.
For an application whose back end already runs on AWS, the integration story is hard to beat. API Gateway and AppSync authorizers, ALB authentication, IAM roles per user and infrastructure-as-code for the whole thing are all native.
The permanent decisions
Several Cognito user pool properties are fixed when the pool is created:
- Which attributes are required. You can't later switch an attribute between required and optional.
- Custom attributes can't be deleted or renamed. You can add more, up to a limit, but not remove any.
- How users sign in, meaning whether a username, email address or phone number identifies them, is chosen at creation.
The documented fix for each is to create a new pool and migrate the users. That's where the design choices compound, because Cognito doesn't export password hashes. A CSV export gives you users without credentials. The users either reset their passwords, or you migrate them lazily, verifying each password against the old pool as each user next signs in.
The mechanism for lazy migration into a Cognito pool is the migrate user Lambda trigger. When a user who doesn't exist yet signs in, Cognito passes the username and password to your function. The function checks them against the old store and returns the user's attributes, and Cognito creates the user with a fresh password verifier. It's a good, documented pattern. The same one is described in Migrating Password Hashes Without Resetting Users.
Notice the asymmetry. Cognito makes it straightforward to migrate into a pool. Migrating out, whether to a new pool or another vendor, depends entirely on the destination being able to run code at sign-in that calls Cognito's authentication API with the user's password. The exit cost isn't set by Cognito's export features. It's set by the extensibility of whatever comes next.
The same test, applied to ClavionX
That last point applies to ClavionX too, and it should be said directly.
ClavionX would be a poor destination for a Cognito migration without password resets. It doesn't run customer code at sign-in, so it has no equivalent of the migrate-user trigger that would verify a password against Cognito and import the user. The only external password authority it supports is an LDAP or Active Directory directory. Moving users from Cognito to ClavionX today means a password reset or a passwordless enrollment for each user. The design principle that keeps ClavionX's login path free of dependencies makes it harder to arrive at.
On the exit side, ClavionX has its own form of the same constraint. Password hashes never appear in API responses, domain events or runtime caches. That's deliberate, and it keeps credentials out of places they can leak. The difference is who holds the database. If you self-host ClavionX, the Argon2 hashes are in your own Postgres, and a future migration can take them with you. On the hosted service, there's no documented hash export today. Migrating Off an Identity Provider Without Downtime recommends asking every vendor about this before you sign, and ClavionX shouldn't be exempt.
On schema, ClavionX is more forgiving, though not entirely. A tenant's custom attributes can change their display name, validation rules, claim mappings and signup placement after creation, and attributes can be deleted. The attribute key and data type are fixed. A rename is therefore still a new attribute plus a data migration. The constraint is the same kind as Cognito's, just narrower: pick keys the way you'd pick column names.
Lambda triggers: five seconds, three attempts
Cognito customizes the flow through Lambda triggers: pre sign-up, pre authentication, post authentication, pre token generation, custom message, the custom authentication challenge triggers, and migrate user. It's a code-extension model, much like Auth0's Actions, except that the code runs in your AWS account as ordinary Lambda functions.
The budget is strict and, importantly, not configurable. Your function must respond within five seconds. If it doesn't, Cognito may retry, and after three unsuccessful attempts the operation fails. Those retries matter more than the timeout. Suppose a pre-token-generation trigger calls a database that's struggling. Every slow sign-in becomes up to three invocations against the dependency that's already slow. That's the load amplification described in Why Identity Systems Fail Gradually, Then All at Once, with the multiplier written into the platform. Lambda cold starts are also counted against the same five seconds.
The series table, extended once more:
| Platform | Synchronous customer logic | Budget |
|---|---|---|
| Auth0 | Your Node.js code, in their sandbox | 20 s |
| Cognito | Your Lambda, in your account | 5 s, up to 3 attempts |
| Okta | Your service, called by them | 3 s |
| Entra | Your service, called by them | 2 s, with retries |
| ClavionX | None | Not applicable |
Running the code in your own account has one real advantage. You get your own logs, metrics, alarms, IAM permissions and VPC access for the extension, rather than a vendor's sandbox. The observability problem from The Extensibility Trap is smaller when the code lives somewhere you already watch.
One commercial detail matters architecturally. Customizing access-token claims requires Essentials or above. On Lite, the pre-token-generation trigger can shape the ID token but not the access token. If your APIs authorize on custom claims, the plan decision is also an architecture decision.
Multi-Region: a read replica for identity
Until mid-2026, a Cognito user pool lived in exactly one Region, and regional failover was an architecture you had to build yourself, usually badly. Multi-Region replication changed that. A replica pool in a standby Region shares the primary's user pool ID and receives users, credentials and configuration in near real time. During a regional disruption, traffic can move to the replica, and existing users can sign in and receive tokens.
The design is instructive. The primary stays authoritative for writes: sign-ups, password resets, administrative changes. The replica serves authentication. That's the read-heavy structure argued for in Identity Is Mostly Read Traffic. Logins are reads against replicated state, and the rare writes go to one place. During a failover, the things that can't happen are the writes, which is the right degradation, as The Cost of Multi-Region Identity argues.
ClavionX has no equivalent managed feature. Its runtime is built around the same principle: logins read projected state and never call the control plane synchronously. But turning that into a multi-Region deployment is currently your architecture to design and operate, not a checkbox.
Tenancy, and a SAML gap worth knowing
Cognito's multi-tenancy guidance offers several patterns, including a pool per tenant, an app client per tenant, and a shared pool with a tenant attribute. Each trades isolation against operational overhead and per-pool quotas. A pool per tenant gives each customer separate keys and configuration, and it also multiplies the permanent decisions above by the number of tenants.
ClavionX makes the tenant the security domain directly. Each tenant has its own OIDC issuer and signing keys, and applications are either scoped to one tenant or declared global with a posture tenants can't loosen. For B2B products that's closer to the shape of the problem.
One concrete capability difference: Cognito user pools can federate from SAML identity providers, but can't act as a SAML identity provider. If your product needs to issue SAML assertions to downstream service providers, for example so users signed in to your platform can reach a partner's SAML-only application, Cognito can't do it. ClavionX can, supporting both SP- and IdP-initiated sign-in with managed certificate rotation. Its own docs note one gap: it doesn't yet verify signatures on inbound AuthnRequests. Keycloak, Okta, Entra and Ping can act as SAML identity providers too.
Where Cognito is simply stronger
- AWS credentials for end users. Identity pools let a client exchange a sign-in for scoped, temporary IAM credentials. Nothing else in this series does this as natively. Any standards-compliant OIDC issuer, ClavionX included, can be registered as an IAM OIDC identity provider for
AssumeRoleWithWebIdentity. Identity pools make it the default path rather than a project. - Infrastructure as code, end to end. User pools, clients, triggers and domains are all CloudFormation resources, reviewed and deployed with the rest of the stack.
- Operations you never see. There's no server, no patching and no capacity planning, and now a managed regional failover.
- Adaptive authentication today, on the Plus plan. ClavionX's is planned.
- Cost at small and moderate scale, especially on Lite, where the price of an identity service is hard to beat.
When Cognito is the better choice
Pick Cognito when:
- The application lives in AWS and you want identity to be one more resource in the stack.
- Clients need direct, per-user access to AWS services through identity pools.
- It's a consumer or simple B2B application whose requirements you can predict well enough to make the day-one decisions confidently.
- You want no identity infrastructure to run, and AWS-native operations are a feature to you, not a lock-in.
ClavionX fits better when you need to act as a SAML identity provider, when you're building a multi-tenant B2B product with per-tenant issuers and keys, or when the identity layer has to run outside a single cloud or inside your own infrastructure. It also fits when you'd rather have no synchronous extensions at all than a five-second, three-attempt one.
The actual difference
Cognito is an excellent AWS primitive. Like most primitives, it asks you to commit early to decisions that are expensive to revisit, and it keeps the credential material that would make revisiting them cheap. ClavionX asks for fewer permanent decisions, but it has its own locked-in choices and its own asymmetry: it's easier to leave, especially self-hosted, and harder to arrive at without password resets.
Whichever you choose, the four-minute setup is the moment to be slow. Write down the sign-in identifier, the required attributes and the attribute names as if they were a database schema you can never migrate, because on some platforms that's exactly what they are.
Vendor details are from AWS's public Cognito documentation and announcements as of September 2026. ClavionX capability status is taken from its public docs and feature matrix. I work on ClavionX.