SuperTokens is an open-source alternative to Auth0 that provides self-hosted authentication, customizable login SDKs, and local session verification.
Commercial identity platforms like Auth0 lock user credential databases behind hosted subscription tiers and bill applications per monthly active user. SuperTokens decouples authentication from proprietary cloud infrastructure by running core authentication services on your own database with local session verification. The result keeps identity records, session state, and security policies fully within your development and deployment workflows.
Auth0 routes authentication flows through an external cloud tenancy and universal login domains, requiring webhooks and dashboard rules to tailor user lifecycles. SuperTokens approaches identity from inside the application architecture. Its decoupled model combines a self-hosted core HTTP service with native backend and frontend software development kits. Because session verification happens in-memory on your application backend using public key cryptography, protected API endpoints authenticate requests without contacting the core service or introducing external network latency.
For engineering teams, the primary advantage centers on workflow integration. Instead of writing isolated dashboard actions in a proprietary console, developers override sign-up handlers, password hashing, and token claims directly in their Node.js, Python, or Go codebases. User accounts, metadata tables, and password hashes stay inside your primary PostgreSQL or MySQL cluster, eliminating external database sync scripts. The trade-off is operational ownership: rather than delegating uptime to a hosted vendor, DevOps engineers must deploy, patch, and monitor the Java-based core service and manage database connection scaling during traffic spikes.
Can SuperTokens completely replace Auth0? Yes, SuperTokens replaces hosted authentication, social logins, session management, and user metadata while running on your own infrastructure. You retain ownership of user records and eliminate per-user SaaS subscription charges.
Is SuperTokens free for commercial use? Yes, the core engine and standard SDK recipes are free for commercial products without user caps or seat fees. Organizations pay only for managed cloud hosting or enterprise directory integrations.
What infrastructure is required to self-host SuperTokens? Self-hosting requires running the SuperTokens Core service in a Docker container or standalone binary backed by PostgreSQL or MySQL. Application servers then use official backend SDKs to communicate with the core and verify sessions locally.
SuperTokens is a practical fit for development teams that require complete custody of their authentication database and want identity logic woven into their codebase rather than outsourced to a hosted service. While running the core service demands container monitoring and Java runtime management, active project maintenance and permissive Apache-2.0 terms make it an adaptable foundation for modern application security.
We started this exact setup from scratch in a clean Linux machine on Nov 1, 2026 and checked it through SuperTokens's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p supertokens && cd supertokens
curl -fsSL https://open-source.store/tools/supertokens/compose.yml -o compose.ymlcat > .env <<EOF
SUPERTOKENS_API_KEY=$(openssl rand -hex 16)
POSTGRES_PASSWORD=$(openssl rand -hex 12)
EOFSUPERTOKENS_API_KEY — API key required for backend SDKs and clients to authenticate with the core. Generated above; keep it secret.POSTGRES_PASSWORD — Password for the bundled PostgreSQL database user. Generated above; keep it secret.docker compose up -dservices:
supertokens:
image: supertokens/supertokens-postgresql:12.4.1
ports:
- "3567:3567"
environment:
POSTGRESQL_CONNECTION_URI: postgresql://supertokens:${POSTGRES_PASSWORD}@db:5432/supertokens
API_KEYS: ${SUPERTOKENS_API_KEY}
depends_on:
db:
condition: service_healthy
restart: always
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3567/hello"]
interval: 5s
timeout: 5s
retries: 5
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: supertokens
POSTGRES_USER: supertokens
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- supertokens-db-data:/var/lib/postgresql/data
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
volumes:
supertokens-db-data:
Free IDE for Java, Kotlin, Go, TypeScript and Python. Built on IntelliJ Community, fully open source, 300+ plugins.
Show that SuperTokens is listed as an open-source alternative. Paste into your README:
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 82 s: supertokens/supertokens-postgresql:12.4.1, postgres:15-alpine.
Based on the upstream setup. Official PostgreSQL deployment from supertokens-core. Image pinned to 12.4.1; database password and API key moved to .env.
supertokens-1 | 2026-11-01T11:13:54.869060637Z Picked up _JAVA_OPTIONS: -Djava.io.tmpdir=/lib/supertokens/temp/ supertokens-1 | 2026-11-01T11:13:54.955378553Z Picked up _JAVA_OPTIONS: -Djava.io.tmpdir=/lib/supertokens/temp/ supertokens-1 | 2026-11-01T11:13:55.329641512Z Loading supertokens config. supertokens-1 | 2026-11-01T11:13:55.331012220Z Completed config.yaml loading. supertokens-1 | 2026-11-01T11:13:55.331277304Z Loading supertokens version.yaml file. supertokens-1 | 2026-11-01T11:13:55.346501762Z OpenTelemetry telemetry disabled: no otel_collector_connection_uri configured. supertokens-1 | 2026-11-01T11:13:55.349005762Z Loading storage layer. supertokens-1 | 2026-11-01T11:13:55.356958345Z Loading PostgreSQL config. supertokens-1 | 2026-11-01T11:13:55.484707887Z Setting up PostgreSQL connection pool. supertokens-1 | 2026-11-01T11:13:56.092454346Z Setting up PostgreSQL connection pool. supertokens-1 | 2026-11-01T11:13:57.615922680Z Started SuperTokens on 0.0.0.0:3567 with PID: 28 db-1 | 2026-11-01T11:13:49.257851634Z The files belonging to this database system will be owned by user "postgres". db-1 | 2026-11-01T11:13:49.257885342Z This user must also own the server process. db-1 | 2026-11-01T11:13:49.257887342Z db-1 | 2026-11-01T11:13:49.258052759Z The database cluster will be initialized with locale "en_US.utf8". db-1 | 2026-11-01T11:13:49.258057801Z The default database encoding has accordingly been set to "UTF8". db-1 | 2026-11-01T11:13:49.258059134Z The default text search configuration will be set to "english". db-1 | 2026-11-01T11:13:49.258060092Z db-1 | 2026-11-01T11:13:49.258060884Z Data page checksums are disabled. db-1 | 2026-11-01T11:13:49.258094301Z db-1 | 2026-11-01T11:13:49.258305009Z fixing permissions on existing directory /var/lib/postgresql/data ... ok db-1 | 2026-11-01T11:13:49.260386676Z creating subdirectories ... ok db-1 | 2026-11-01T11:13:49.260442342Z selecting dynamic shared memory implementation ... posix db-1 | 2026-11-01T11:13:49.271101467Z selecting default max_connections ... 100 db-1 | 2026-11-01T11:13:49.283499176Z selecting default shared_buffers ... 128MB db-1 | 2026-11-01T11:13:49.301709426Z selecting default time zone ... UTC db-1 | 2026-11-01T11:13:49.303050301Z creating configuration files ... ok db-1 | 2026-11-01T11:13:49.372071009Z running bootstrap script ... ok db-1 | 2026-11-01T11:13:49.455501301Z sh: locale: not found db-1 | 2026-11-01T11:13:49.457812426Z 2026-11-01 11:13:49.455 UTC [34] WARNING: no usable system locales were found db-1 | 2026-11-01T11:13:49.634510343Z performing post-bootstrap initialization ... ok db-1 | 2026-11-01T11:13:49.693280051Z initdb: warning: enabling "trust" authentication for local connections db-1 | 2026-11-01T11:13:49.693297676Z initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. db-1 | 2026-11-01T11:13:49.693297134Z syncing data to disk ... ok db-1 | 2026-11-01T11:13:49.693303218Z db-1 | 2026-11-01T11:13:49.693304676Z db-1 | 2026-11-01T11:13:49.693305593Z Success. You can now start the database server using: db-1 | 2026-11-01T11:13:49.693306468Z db-1 | 2026-11-01T11:13:49.693307218Z pg_ctl -D /var/lib/postgresql/data -l logfile start db-1 | 2026-11-01T11:13:49.693308009Z db-1 | 2026-11-01T11:13:49.715977676Z waiting for server to start....2026-11-01 11:13:49.715 UTC [40] LOG: starting PostgreSQL 15.19 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit db-1 | 2026-11-01T11:13:49.716783051Z 2026-11-01 11:13:49.716 UTC [40] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db-1 | 2026-11-01T11:13:49.718958134Z 2026-11-01 11:13:49.718 UTC [43] LOG: database system was shut down at 2026-11-01 11:13:49 UTC db-1 | 2026-11-01T11:13:49.720708176Z 2026-11-01 11:13:49.720 UTC [40] LOG: database system is ready to accept connections db-1 | 2026-11-01T11:13:49.806319634Z done db-1 | 2026-11-01T11:13:49.806334468Z server started db-1 | 2026-11-01T11:13:49.832812343Z CREATE DATABASE db-1 | 2026-11-01T11:13:49.834358093Z db-1 | 2026-11-01T11:13:49.834393009Z db-1 | 2026-11-01T11:13:49.834418843Z /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* db-1 | 2026-11-01T11:13:49.834420468Z db-1 | 2026-11-01T11:13:49.834827468Z waiting for server to shut down....2026-11-01 11:13:49.834 UTC [40] LOG: received fast shutdown request db-1 | 2026-11-01T11:13:49.835732176Z 2026-11-01 11:13:49.835 UTC [40] LOG: aborting any active transactions db-1 | 2026-11-01T11:13:49.837638884Z 2026-11-01 11:13:49.837 UTC [40] LOG: background worker "logical replication launcher" (PID 46) exited with exit code 1 db-1 | 2026-11-01T11:13:49.837808676Z 2026-11-01 11:13:49.837 UTC [41] LOG: shutting down db-1 | 2026-11-01T11:13:49.838465634Z 2026-11-01 11:13:49.838 UTC [41] LOG: checkpoint starting: shutdown immediate db-1 | 2026-11-01T11:13:49.864944509Z 2026-11-01 11:13:49.864 UTC [41] LOG: checkpoint complete: wrote 922 buffers (5.6%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.009 s, sync=0.017 s, total=0.028 s; sync files=301, longest=0.005 s, average=0.001 s; distance=4249 kB, estimate=4249 kB db-1 | 2026-11-01T11:13:49.867715718Z 2026-11-01 11:13:49.867 UTC [40] LOG: database system is shut down db-1 | 2026-11-01T11:13:49.935202134Z done db-1 | 2026-11-01T11:13:49.935223718Z server stopped db-1 | 2026-11-01T11:13:49.935670968Z db-1 | 2026-11-01T11:13:49.935675176Z PostgreSQL init process complete; ready for start up. db-1 | 2026-11-01T11:13:49.935676218Z db-1 | 2026-11-01T11:13:49.947864968Z 2026-11-01 11:13:49.947 UTC [1] LOG: starting PostgreSQL 15.19 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit db-1 | 2026-11-01T11:13:49.947959426Z 2026-11-01 11:13:49.947 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 db-1 | 2026-11-01T11:13:49.948018259Z 2026-11-01 11:13:49.947 UTC [1] LOG: listening on IPv6 address "::", port 5432 db-1 | 2026-11-01T11:13:49.949247218Z 2026-11-01 11:13:49.949 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db-1 | 2026-11-01T11:13:49.951487176Z 2026-11-01 11:13:49.951 UTC [56] LOG: database system was shut down at 2026-11-01 11:13:49 UTC db-1 | 2026-11-01T11:13:49.953525426Z 2026-11-01 11:13:49.953 UTC [1] LOG: database system is ready to accept connections db-1 | 2026-11-01T11:13:56.115062721Z 2026-11-01 11:13:56.114 UTC [76] ERROR: duplicate key value violates unique constraint "tenants_pkey" db-1 | 2026-11-01T11:13:56.115085262Z 2026-11-01 11:13:56.114 UTC [76] DETAIL: Key (app_id, tenant_id)=(public, public) already exists. db-1 | 2026-11-01T11:13:56.115087304Z 2026-11-01 11:13:56.114 UTC [76] STATEMENT: INSERT INTO tenants(app_id, tenant_id, created_at_time) VALUES($1, $2, $3)