diff --git a/src/components/cost-calculator/CostCalculator.astro b/src/components/cost-calculator/CostCalculator.astro new file mode 100644 index 0000000..a8a36da --- /dev/null +++ b/src/components/cost-calculator/CostCalculator.astro @@ -0,0 +1,278 @@ +--- +// The static tables are the no-JavaScript version of the calculator, so they print every +// published price in pricing.ts and nothing the script could not also show. +import { + type Auth0Plan, + auth0MauSteps, + auth0Plans, + okta, + selfHost, + selfHostMonthlyUsd, + sources, + usd, +} from './pricing' + +const plansFor = (useCase: 'b2c' | 'b2b') => auth0Plans.filter((plan) => plan.useCase === useCase) + +type Cell = { text: string; salesUrl?: string } + +const cell = (plan: Auth0Plan, mau: number): Cell => { + const tier = plan.tiers.find((t) => mau <= t.upToMau) + if (tier) return { text: usd(tier.monthlyUsd) } + if (plan.aboveTiers === 'unavailable') return { text: 'Not on plan' } + return { text: 'Contact sales', salesUrl: sources.auth0Sales.url } +} + +const steps = [ + ...auth0MauSteps.map((mau) => ({ label: mau.toLocaleString('en-US'), mau })), + { label: 'Above 30,000', mau: Number.POSITIVE_INFINITY }, +] + +const selfHostSummary = `${usd(selfHostMonthlyUsd)} per month at any MAU (${selfHost.provider} ${usd( + selfHost.app.monthlyUsd, +)} Droplet plus ${usd(selfHost.database.monthlyUsd)} managed PostgreSQL, checked ${ + selfHost.app.source.checked +})` +--- + +
+ + + + +
+

+ Auth0 list prices per month, monthly billing, from auth0.com/pricing (checked {sources.auth0.checked}). A MAU count between two steps uses the next step up. +

+ { + (['b2c', 'b2b'] as const).map((useCase) => ( + + + + + + {plansFor(useCase).map((plan) => ( + + ))} + + + + + {steps.map(({ label, mau }) => ( + + + {plansFor(useCase).map((plan) => { + const { text, salesUrl } = cell(plan, mau) + return + })} + + + ))} + +
Auth0 {useCase === 'b2c' ? 'B2C' : 'B2B'} plans
MAU up to{plan.name}Enterprise
{label}{salesUrl ? {text} : text} + Contact sales +
+ )) + } +

+ Okta Customer Identity, from okta.com/pricing (checked { + sources.okta.checked + }): the Enterprise base platform starts at {usd(okta.basePlatformFromUsd)} per month, { + okta.billing + }, with usage-priced add-ons quoted by sales. The B2C Suite and B2B Suite are contact sales. +

+

Seamless Auth self-hosted: {selfHostSummary}.

+
+
+ + + + diff --git a/src/components/cost-calculator/pricing.ts b/src/components/cost-calculator/pricing.ts new file mode 100644 index 0000000..98cb70c --- /dev/null +++ b/src/components/cost-calculator/pricing.ts @@ -0,0 +1,360 @@ +// Every price on the Identity Cost Calculator page comes from this file. Each value was read +// from the vendor's own page on the `checked` date of its source. Re-check them all on the day +// the page is republished, and never add a price the source does not print. + +export type UseCase = 'b2c' | 'b2b' +export type Mfa = 'none' | 'otp' | 'enterprise' + +export interface Source { + label: string + url: string + checked: string +} + +export const sources = { + auth0: { + label: 'Auth0 pricing', + url: 'https://auth0.com/pricing', + checked: '2026-10-21', + }, + auth0Sales: { + label: 'Auth0 sales', + url: 'https://auth0.com/contact-us', + checked: '2026-10-21', + }, + okta: { + label: 'Okta plans and pricing, Customer Identity tab', + url: 'https://www.okta.com/pricing/', + checked: '2026-10-21', + }, + oktaSales: { + label: 'Okta sales', + url: 'https://www.okta.com/contact-sales/', + checked: '2026-10-21', + }, + doDroplets: { + label: 'DigitalOcean Droplet pricing', + url: 'https://www.digitalocean.com/pricing/droplets', + checked: '2026-10-21', + }, + doDatabases: { + label: 'DigitalOcean Managed Databases pricing', + url: 'https://www.digitalocean.com/pricing/managed-databases', + checked: '2026-10-21', + }, + doPostgresDocs: { + label: 'DigitalOcean PostgreSQL pricing details', + url: 'https://docs.digitalocean.com/products/databases/postgresql/details/pricing/', + checked: '2026-10-21', + }, +} satisfies Record + +export interface Tier { + upToMau: number + monthlyUsd: number +} + +export type Availability = 'included' | 'add-on' | 'not-included' | 'not-listed' + +export interface Auth0Plan { + id: string + name: string + useCase: UseCase + // Monthly billing. A MAU above the last tier is "Get in touch" on the pricing page. + tiers: Tier[] + // Free has no sales path, only a MAU ceiling. + aboveTiers: 'contact' | 'unavailable' + enterpriseConnections: { included: number; addOnFromUsd: number | null } + mfaOtp: Availability + mfaEnterprise: Availability + mfaEnterpriseAddOnFromUsd: number | null +} + +const free = (useCase: UseCase): Auth0Plan => ({ + id: `${useCase}-free`, + name: 'Free', + useCase, + tiers: [{ upToMau: 25000, monthlyUsd: 0 }], + aboveTiers: 'unavailable', + enterpriseConnections: { included: 1, addOnFromUsd: null }, + mfaOtp: 'not-included', + mfaEnterprise: 'not-listed', + mfaEnterpriseAddOnFromUsd: null, +}) + +export const auth0Plans: Auth0Plan[] = [ + free('b2c'), + { + id: 'b2c-essentials', + name: 'Essentials', + useCase: 'b2c', + tiers: [ + { upToMau: 500, monthlyUsd: 35 }, + { upToMau: 1000, monthlyUsd: 70 }, + { upToMau: 2500, monthlyUsd: 175 }, + { upToMau: 5000, monthlyUsd: 350 }, + { upToMau: 7500, monthlyUsd: 525 }, + { upToMau: 10000, monthlyUsd: 700 }, + { upToMau: 20000, monthlyUsd: 1400 }, + { upToMau: 30000, monthlyUsd: 2100 }, + ], + aboveTiers: 'contact', + enterpriseConnections: { included: 0, addOnFromUsd: null }, + mfaOtp: 'included', + mfaEnterprise: 'not-listed', + mfaEnterpriseAddOnFromUsd: null, + }, + { + id: 'b2c-professional', + name: 'Professional', + useCase: 'b2c', + tiers: [ + { upToMau: 500, monthlyUsd: 240 }, + { upToMau: 1000, monthlyUsd: 240 }, + { upToMau: 2500, monthlyUsd: 545 }, + { upToMau: 5000, monthlyUsd: 1000 }, + { upToMau: 7500, monthlyUsd: 1200 }, + { upToMau: 10000, monthlyUsd: 1600 }, + { upToMau: 20000, monthlyUsd: 3200 }, + ], + aboveTiers: 'contact', + enterpriseConnections: { included: 0, addOnFromUsd: null }, + mfaOtp: 'included', + mfaEnterprise: 'included', + mfaEnterpriseAddOnFromUsd: null, + }, + free('b2b'), + { + id: 'b2b-essentials', + name: 'Essentials', + useCase: 'b2b', + tiers: [ + { upToMau: 500, monthlyUsd: 150 }, + { upToMau: 1000, monthlyUsd: 300 }, + { upToMau: 2500, monthlyUsd: 700 }, + { upToMau: 5000, monthlyUsd: 1300 }, + { upToMau: 7500, monthlyUsd: 1725 }, + { upToMau: 10000, monthlyUsd: 2100 }, + { upToMau: 20000, monthlyUsd: 3800 }, + ], + aboveTiers: 'contact', + enterpriseConnections: { included: 3, addOnFromUsd: 100 }, + mfaOtp: 'included', + mfaEnterprise: 'add-on', + mfaEnterpriseAddOnFromUsd: 100, + }, + { + id: 'b2b-professional', + name: 'Professional', + useCase: 'b2b', + tiers: [ + { upToMau: 500, monthlyUsd: 800 }, + { upToMau: 1000, monthlyUsd: 800 }, + { upToMau: 2500, monthlyUsd: 1200 }, + { upToMau: 5000, monthlyUsd: 1500 }, + { upToMau: 7500, monthlyUsd: 1800 }, + { upToMau: 10000, monthlyUsd: 2400 }, + ], + aboveTiers: 'contact', + enterpriseConnections: { included: 5, addOnFromUsd: 100 }, + mfaOtp: 'included', + mfaEnterprise: 'included', + mfaEnterpriseAddOnFromUsd: null, + }, +] + +// The MAU steps on Auth0's pricing slider, used for the static table. +export const auth0MauSteps = [500, 1000, 2500, 5000, 7500, 10000, 20000, 30000] + +export const okta = { + basePlatformFromUsd: 3000, + billing: 'billed annually', +} + +export const selfHost = { + provider: 'DigitalOcean', + region: 'any DigitalOcean region (the pricing pages list one price, not a price per region)', + app: { + name: 'Basic Droplet, Regular CPU, 2 GiB memory, 1 vCPU, 50 GiB SSD, 2,000 GiB transfer', + monthlyUsd: 12, + source: sources.doDroplets, + }, + database: { + name: 'Managed PostgreSQL, Standard Edition, Basic node, 1 GiB memory, 1 vCPU, single node, 10 GiB storage', + monthlyUsd: 15.15, + source: sources.doDatabases, + }, + extraStoragePerGibUsd: 0.215, +} + +export const selfHostMonthlyUsd = selfHost.app.monthlyUsd + selfHost.database.monthlyUsd + +export interface Inputs { + mau: number + useCase: UseCase + enterpriseConnections: number + mfa: Mfa +} + +export type Quote = + | { kind: 'price'; usd: number; notes: string[] } + | { kind: 'from'; usd: number; notes: string[] } + | { kind: 'contact'; notes: string[] } + | { kind: 'unavailable'; notes: string[] } + +export interface Row { + vendor: 'Auth0' | 'Okta Customer Identity' | 'Seamless Auth' + plan: string + quote: Quote + salesUrl?: string +} + +export function usd(value: number): string { + return value.toLocaleString('en-US', { + style: 'currency', + currency: 'USD', + minimumFractionDigits: Number.isInteger(value) ? 0 : 2, + maximumFractionDigits: 2, + }) +} + +export function auth0Quote(plan: Auth0Plan, inputs: Inputs): Quote { + const tier = plan.tiers.find((t) => inputs.mau <= t.upToMau) + if (!tier) { + const top = plan.tiers[plan.tiers.length - 1].upToMau.toLocaleString('en-US') + if (plan.aboveTiers === 'unavailable') { + return { kind: 'unavailable', notes: [`${plan.name} covers up to ${top} MAU.`] } + } + return { + kind: 'contact', + notes: [`The pricing page prints no ${plan.name} price above ${top} MAU.`], + } + } + + const notes: string[] = [] + let extra = 0 + let startingPrice = false + + const { included, addOnFromUsd } = plan.enterpriseConnections + if (inputs.enterpriseConnections > included) { + if (addOnFromUsd === null) { + return { + kind: 'unavailable', + notes: [ + included === 0 + ? `The pricing page lists no enterprise connections on ${useCaseName(plan.useCase)} ${plan.name}.` + : `${plan.name} includes ${included} enterprise connection and lists no add-on for more.`, + ], + } + } + const added = inputs.enterpriseConnections - included + extra += added * addOnFromUsd + startingPrice = true + notes.push( + `${included} enterprise connections included; ${added} more at a starting price of ${usd(addOnFromUsd)} a month each.`, + ) + } else if (inputs.enterpriseConnections > 0) { + notes.push(`Includes ${included} enterprise connection${included === 1 ? '' : 's'}.`) + } + + if (inputs.mfa === 'otp' && plan.mfaOtp !== 'included') { + return { + kind: 'unavailable', + notes: [`The pricing page lists Pro MFA (OTP apps, Duo) as not included on ${plan.name}.`], + } + } + if (inputs.mfa === 'enterprise') { + if (plan.mfaEnterprise === 'add-on' && plan.mfaEnterpriseAddOnFromUsd !== null) { + extra += plan.mfaEnterpriseAddOnFromUsd + startingPrice = true + notes.push( + `Enterprise MFA add-on at a starting price of ${usd(plan.mfaEnterpriseAddOnFromUsd)} a month; SMS is charged separately by carriers.`, + ) + } else if (plan.mfaEnterprise !== 'included') { + return { + kind: 'unavailable', + notes: [ + `The pricing page does not list Enterprise MFA (SMS, voice, email, WebAuthn, push) on ${useCaseName(plan.useCase)} ${plan.name}.`, + ], + } + } + } + + const upTo = tier.upToMau.toLocaleString('en-US') + notes.unshift(`Tier: up to ${upTo} MAU, monthly billing.`) + const total = tier.monthlyUsd + extra + return startingPrice ? { kind: 'from', usd: total, notes } : { kind: 'price', usd: total, notes } +} + +export function oktaRows(inputs: Inputs): Row[] { + const addOns: string[] = [] + if (inputs.mfa !== 'none') addOns.push('MFA') + if (inputs.enterpriseConnections > 0) addOns.push('Inbound Federation') + const base: Row = { + vendor: 'Okta Customer Identity', + plan: 'Enterprise base platform', + salesUrl: sources.oktaSales.url, + quote: { + kind: 'from', + usd: okta.basePlatformFromUsd, + notes: [ + `Starting price, ${okta.billing}. Add-ons are priced on usage such as MAU and quoted by sales; the page publishes no price per MAU.`, + ...(addOns.length + ? [ + `${addOns.join(' and ')}: add-on${addOns.length > 1 ? 's' : ''} with no published price.`, + ] + : []), + ], + }, + } + const suite: Row = { + vendor: 'Okta Customer Identity', + plan: inputs.useCase === 'b2c' ? 'B2C Suite' : 'B2B Suite', + salesUrl: sources.oktaSales.url, + quote: { kind: 'contact', notes: ['Inquire for pricing.'] }, + } + return [base, suite] +} + +export function seamlessRow(inputs: Inputs): Row { + const notes = [ + `${selfHost.provider} ${usd(selfHost.app.monthlyUsd)} Droplet plus ${usd(selfHost.database.monthlyUsd)} managed PostgreSQL. No per-user fee, so the cost does not change with MAU.`, + ] + if (inputs.enterpriseConnections > 0) { + notes.push( + 'Seamless Auth has no SAML or per-customer enterprise connections; OAuth and OIDC providers are configured instance-wide.', + ) + } + if (inputs.mfa === 'enterprise') { + notes.push( + 'Second factors are TOTP and passkey (WebAuthn) step-up; there is no push or SMS second factor.', + ) + } + return { + vendor: 'Seamless Auth', + plan: 'Self-hosted', + quote: { kind: 'price', usd: selfHostMonthlyUsd, notes }, + } +} + +export function calculate(inputs: Inputs): Row[] { + const auth0Rows: Row[] = auth0Plans + .filter((plan) => plan.useCase === inputs.useCase) + .map((plan) => ({ + vendor: 'Auth0', + plan: plan.name, + quote: auth0Quote(plan, inputs), + salesUrl: sources.auth0Sales.url, + })) + auth0Rows.push({ + vendor: 'Auth0', + plan: 'Enterprise', + quote: { kind: 'contact', notes: ['Priced by Auth0 sales.'] }, + salesUrl: sources.auth0Sales.url, + }) + return [...auth0Rows, ...oktaRows(inputs), seamlessRow(inputs)] +} + +function useCaseName(useCase: UseCase): string { + return useCase === 'b2c' ? 'B2C' : 'B2B' +} diff --git a/src/content/docs/compare/auth0.mdx b/src/content/docs/compare/auth0.mdx index c4dcfcc..acb5e9f 100644 --- a/src/content/docs/compare/auth0.mdx +++ b/src/content/docs/compare/auth0.mdx @@ -65,7 +65,8 @@ on [auth0.com/pricing](https://auth0.com/pricing) before you decide. plan. - **You prefer not to pay per active user or per enterprise connection.** Self-hosting has no per-user fee; you pay for the infrastructure you run. Auth0 plans scale with monthly active users, and its - pricing page lists a charge for each enterprise SSO connection above a plan's allowance. + pricing page lists a charge for each enterprise SSO connection above a plan's allowance. The + [Identity Cost Calculator](/compare/cost) puts both side by side for your numbers. - **You want your user data in a database you can query.** Self-hosted, users, memberships, and auth events are rows in a Postgres database you run, and the auth event trail exports as a hash-chained file you can verify. Auth0's bulk user export is not on its Free plan, and a password @@ -107,12 +108,13 @@ page. | Pricing model | Free to self-host; managed plans in the portal | Free plan up to 25,000 MAU; paid plans priced by MAU tier, separate B2C and B2B prices, add-ons for enterprise connections, MFA, and M2M tokens | --- @@ -203,7 +205,7 @@ maintains Seamless Auth, offers hands-on migration help (see the end of that gui Auth0 and Okta details, each checked on the date shown: -- [Auth0 pricing](https://auth0.com/pricing), checked 2026-10-20: plans and starting prices, B2C and B2B split, MAU limits, passkeys on all plans, MFA tiers, Organizations, enterprise connection allowances and add-on price, SCIM, Actions counts, SLA +- [Auth0 pricing](https://auth0.com/pricing), checked 2026-10-20: plans and starting prices, B2C and B2B split, MAU limits, passkeys on all plans, MFA tiers, Organizations, enterprise connection allowances and add-on starting price, SCIM, Actions counts, SLA - [Passkeys](https://auth0.com/docs/authenticate/database-connections/passkeys), checked 2026-10-20: database connections, 20 passkeys per user, existing credentials not replaced - [Passwordless connections](https://auth0.com/docs/authenticate/passwordless), checked 2026-10-20: email and SMS codes, magic links in Classic Login only - [Multi-factor authentication factors](https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors), checked 2026-10-20: factor list, factors depend on plan diff --git a/src/content/docs/compare/cost.mdx b/src/content/docs/compare/cost.mdx new file mode 100644 index 0000000..e0f1837 --- /dev/null +++ b/src/content/docs/compare/cost.mdx @@ -0,0 +1,143 @@ +--- +title: "Identity Cost Calculator" +description: "Compare the published list prices of Auth0 and Okta Customer Identity plans with the cost of self-hosting Seamless Auth on one container and managed Postgres, by monthly active users, B2B or B2C, enterprise connections, and MFA. List prices only, each dated and sourced." +sidebar: + order: 20 +--- + +import { Aside } from '@astrojs/starlight/components'; +import CostCalculator from '../../../components/cost-calculator/CostCalculator.astro'; +import { selfHost, selfHostMonthlyUsd, usd } from '../../../components/cost-calculator/pricing'; + +The bill is often the first reason a team looks past its identity provider. This page puts a number +on it: enter your monthly active users (MAU), whether you sell to consumers (B2C) or businesses +(B2B), how many enterprise connections you need, and what kind of MFA, and it shows the published +list price of each Auth0 and Okta Customer Identity plan next to the cost of running Seamless Auth +yourself. + +These are **list prices only**, read from each vendor's own pricing page on the date given in +[Sources](#sources). They leave out discounts, annual commitments, negotiated contracts, taxes, +and usage charges a page does not print. Where a vendor publishes no price, the calculator says +"Contact sales" and links to the vendor. It never estimates one. + +--- + +## Calculator + + + + + +--- + +## How The Numbers Are Read + +**Auth0.** Auth0's pricing page has a MAU slider with steps at 500, 1,000, 2,500, 5,000, 7,500, +10,000, 20,000, and 30,000+, and separate B2C and B2B prices. The calculator uses the price the +page shows for each plan at each step, on monthly billing, and rounds your MAU up to the next step +(so 6,000 MAU uses the "up to 7,500" price). It does not interpolate between steps. Where a plan +shows "Get in touch" at a step, or your MAU is above 30,000, the calculator shows "Contact sales". +Free covers up to 25,000 MAU and has no paid path above that. Enterprise has no published price. + +**Enterprise connections.** Auth0's Free plan includes 1 enterprise connection (plus unlimited +Okta enterprise connections), B2B Essentials includes 3, and B2B Professional includes 5. The B2C plans +list none on Essentials or Professional; the pricing page tells B2C customers to move to a B2B +plan for enterprise connections. On the B2B plans, extra connections are an add-on that the page +lists at "starting at $100 monthly per active connection", so any result that uses it is shown as +"From" the starting price. The page publishes no add-on for extra connections on Free. + +**MFA.** The pricing page lists Pro MFA (one-time password apps and Duo) on every paid plan but not +on Free, and Enterprise MFA (SMS, voice, email, WebAuthn, and push through Auth0 Guardian) as +included on Professional, an add-on on B2B Essentials "starting at $100 monthly", and not listed on +B2C Essentials or Free. The page notes that SMS for MFA is charged separately by carriers. Where a +plan does not list the MFA you pick, the calculator says so rather than guessing a price. + +**Okta Customer Identity.** Okta's own pricing page has a Customer Identity tab, separate from the +Auth0 pricing page it also links to. It lists an Enterprise base platform starting at $3,000 per +month, billed annually, with add-ons (including MFA and Inbound Federation) priced on usage such as +MAU and quoted by sales, and a B2C Suite and a B2B Suite with no published price. The calculator +shows the base platform as "From $3,000" whatever your inputs, because the page does not say how +MAU, MFA, or federation change it. See also +[Okta Customer Identity](/compare/auth0#okta-customer-identity) on the Auth0 comparison page. + +--- + +## The Seamless Auth Number + +Self-hosted Seamless Auth has no per-user, per-connection, or per-factor fee. You pay for the +infrastructure, so the cost is flat as MAU grows until you choose to add capacity. The calculator +uses one typical setup, priced from DigitalOcean's own pricing pages on 2026-10-21: + +| | Basis | List price | +| --- | --- | --- | +| Provider | DigitalOcean; the pricing pages list one price, not a price per region | | +| Auth API container | Basic Droplet, Regular CPU: 2 GiB memory, 1 vCPU, 50 GiB SSD, 2,000 GiB transfer | {usd(selfHost.app.monthlyUsd)} per month | +| Managed Postgres | Managed PostgreSQL, Standard Edition, Basic node: 1 GiB memory, 1 vCPU, single node, 10 GiB storage | {usd(selfHost.database.monthlyUsd)} per month | +| **Total** | | **{usd(selfHostMonthlyUsd)} per month** | + +DigitalOcean's PostgreSQL pricing details page says single node clusters are not highly available +and recommends them for development and testing, and that high availability clusters begin at +$30.00 per month for the primary node plus at least one matching standby node at $30.00 per month. +The same page says that from 15 October 2026 for new accounts, and 30 November 2026 for all +accounts, new Standard Edition clusters cannot add standby nodes, so a new high availability +cluster needs a different edition. The single node plan the calculator uses is not affected. +Extra storage on a Standard Edition cluster costs $0.215 per GiB per month. That page gives +round starting prices (single node clusters from $15.00 per month); the calculator uses the +$15.15 that the Managed Databases pricing page lists for the plan. + +This is a starting point, not a measured capacity. Seamless Auth has not published a benchmark of +how many users or sign-ins a given size handles. The one measurement on record is an idle API +container using about 73 MiB of memory with an empty database (see the +[Keycloak comparison's Footprint section](/compare/keycloak#footprint)). Size your deployment by +testing it with your own traffic. + +The Seamless Auth number does **not** include: + +- your time to deploy, upgrade, monitor, and secure it, which is the main cost of self-hosting +- backups beyond what your database provider includes, and their storage +- monitoring, logging, and alerting +- email and SMS delivery, which your providers (for example Twilio or AWS SNS) bill you for +- a load balancer, a second app instance, or a high availability database +- domain names and TLS certificates, if you pay for them + +Seamless Auth also does less than Auth0 and Okta. It has no SAML, no per-customer enterprise +connections, no SCIM, and no push or SMS second factor, so if your inputs need those, a lower price +does not mean the same product. The calculator notes this against the Seamless Auth row. See +[Seamless Auth vs Auth0](/compare/auth0) for the full comparison. + +The managed Seamless Auth service is priced in the portal at +[dashboard.seamlessauth.com](https://dashboard.seamlessauth.com); this page does not quote it. + +--- + +## Sources + +Each page was checked on the date shown. All prices are in US dollars. + +- [Auth0 pricing](https://auth0.com/pricing), checked 2026-10-21: Free up to 25,000 MAU; monthly + B2C and B2B prices at each MAU step; "Get in touch" steps; enterprise connection allowances and + the "starting at $100 monthly per active connection" add-on; Pro MFA and Enterprise MFA by plan, + the B2B Essentials Enterprise MFA add-on "starting at $100 monthly", and SMS charged separately; + Enterprise by contact +- [Auth0 contact sales](https://auth0.com/contact-us), checked 2026-10-21 +- [Okta plans and pricing](https://www.okta.com/pricing/), Customer Identity tab, checked + 2026-10-21: Enterprise base platform starting at $3,000 per month billed annually, B2C and B2B + Suites by inquiry, add-ons priced on usage, annual contract required +- [Okta contact sales](https://www.okta.com/contact-sales/), checked 2026-10-21 +- [DigitalOcean Droplet pricing](https://www.digitalocean.com/pricing/droplets), checked + 2026-10-21: Basic Droplet, Regular CPU, 2 GiB, 1 vCPU, $12.00 per month +- [DigitalOcean Managed Databases pricing](https://www.digitalocean.com/pricing/managed-databases), + checked 2026-10-21: PostgreSQL Standard, Basic node, 1 GiB, 1 vCPU, $15.15 per month, storage + range 10 to 30 GiB +- [DigitalOcean PostgreSQL pricing details](https://docs.digitalocean.com/products/databases/postgresql/details/pricing/), + checked 2026-10-21: single node clusters not highly available, high availability from $30.00 per + month per node, no standby nodes on new Standard Edition clusters from 2026-10-15 (new accounts) + and 2026-11-30 (all accounts), extra Standard Edition storage at $0.215 per GiB per month + +The calculator's prices all live in one file, +[`src/components/cost-calculator/pricing.ts`](https://github.com/fells-code/seamless-auth-docs/blob/main/src/components/cost-calculator/pricing.ts), +with the source and checked date next to each, so they can be re-checked in one place. diff --git a/src/content/docs/compare/keycloak.mdx b/src/content/docs/compare/keycloak.mdx index 6a263a8..7cc0c38 100644 --- a/src/content/docs/compare/keycloak.mdx +++ b/src/content/docs/compare/keycloak.mdx @@ -135,6 +135,10 @@ setup with 1,000,000 users and 20,000 clients on OpenJDK 21. Keycloak's containe traffic. +Neither charges a license or per-user fee, so what you pay for is the infrastructure. For a priced +example of one Seamless Auth container plus managed Postgres on a typical host, next to Auth0 and +Okta list prices, see the [Identity Cost Calculator](/compare/cost). + --- ## Setup