supabase/auth: self-hosting the Go server behind Supabase Auth
A JWT based API for managing users and issuing JWT tokens
At a glance
- What is it?
- supabase/auth is the Go authentication server that issues the JWTs Supabase products rely on. It is a self-hosting decision with a schema you are told not to touch, and the README points most teams at the hosted service instead.
- Who is it for?
- Adopt supabase/auth if you already run Supabase components yourself and need the token issuer inside your own network, and you accept that the migrations directory and the users schema are managed by the project rather than by you. Do not adopt it as a general purpose identity provider for an unrelated stack, and do not treat it as a Go library, since the README states there are no backward compatibility guarantees for that use.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What supabase/auth does and who ends up running it
Supabase Auth is a user management and authentication server written in Go. The README lists what it powers inside Supabase: issuing JWTs, Row Level Security with PostgREST, user management, sign in with email, password, magic link and phone number, and sign in with external providers such as Google, Apple, Facebook and Discord. The repository is the server, not a client SDK. If you are building an application on top of a hosted Supabase project, you are already a consumer of this code and you will probably never compile it.
The audience for the repository itself is narrower. You are a candidate to run it yourself if you need the token issuer inside your own network, if you are assembling a Supabase-compatible stack from components, or if you are contributing to the project. The README is blunt about the default: running an authentication server in production is not an easy feat, and it recommends using Supabase Auth, which it says gets regular security updates. That sentence is the most useful line in the document. Everything else in the self-hosting path is written for people who have already decided to ignore it.
The project descends from GoTrue by Netlify, and the README states that the two have diverged significantly in features and capabilities. That history matters when you read the compatibility notes, because a few inherited features are still present in the code but are not supported by Supabase and may be removed without prior notice.
The architecture: one Go binary, one Postgres schema, stateless JWTs
The deployment shape is a single Go binary talking to Postgres. The Dockerfile builds the binary in a golang:1.27.0-alpine3.23 stage, then copies it to an alpine:3 runtime image alongside the migrations directory, which lands at /usr/local/etc/auth/migrations and is wired up through the GOTRUE_DB_MIGRATIONS_PATH environment variable. The image runs as a non-root supabase user and the container command is auth. A symlink named gotrue points at the same binary, which is a leftover from the Netlify lineage.
Configuration comes from environment variables, a .env file, or a mixture of both. Environment variables carry the GOTRUE_ prefix and always take precedence over values from the file. The README's top-level example sets GOTRUE_SITE_URL, described as required, which is the base URL of your site and is used to build URLs that appear in emails. Any URI sharing a host with SITE_URL is accepted as a redirect_to value, and a separate URI_ALLOW_LIST setting takes a comma-separated list of permitted URIs that supports wildcards such as https://*.foo.example.com.
Tokens are JWTs, and the signing story is worth reading twice. Supabase Auth supports asymmetric keys, RS256 by default, with ECC and Ed25519 listed as optional. HS256 is still supported for compatibility, but the README recommends migrating to asymmetric keys for easier validation and rotation. Asymmetric signing is the reason a separate service can verify a token without holding the secret that mints it, which is what makes the PostgREST integration workable. Database migrations are checked into the repository under migrations/, and the README asks self-hosters not to modify the schema that Auth manages.
Installing supabase/auth and getting a health check to pass
The quickest path documented in the README uses Docker. You create a .env.docker file for your own variables, following example.docker.env, then build and start the stack. The Makefile picks docker compose or docker-compose depending on which one it finds on your machine.
make build
make dev
docker psAfter make dev, docker ps should show two containers named auth-auth-1 and auth-postgres-1. The README says to visit the health check endpoint at http://localhost:9999/health to confirm the server is running. If you get a response there, the binary started and reached its database.
If you would rather run the pieces by hand, the README gives a three step sequence: start the Postgres container with docker-compose -f docker-compose-dev.yml up postgres, build the binary with make build, then execute ./auth. The build target invokes go build with a linker flag that stamps the binary with the current git revision.
make build
./authThe Makefile exposes more than the build target. The all target runs check-go-version, vet, sec, static and build, which is the same set of checks you would want in CI. For a first real use, the practical starting point is the endpoint list in the README and openapi.yaml at the repository root, which is the machine-readable description of the REST surface. Set GOTRUE_SITE_URL before you try any flow that sends email, because the README states it is required and that it feeds the URL construction for those messages.
The schema is managed by the project, not by you
The strongest constraint in the README is not a performance limit or a missing feature. It is ownership of the database. Self-hosters are told not to modify the schema managed by Auth, with migrations/ given as the reference for what that schema is, and not to rely on the schema or the structure of data in the database at all. Instead, use the Auth APIs and JWTs to infer information about users.
That is a real design position and it has consequences. If you want to join your application tables to the users table with a foreign key, or add a column that your code reads directly, you are working against the documented guidance. The compatibility promises reinforce it: patch releases guarantee that a column will not change type, that a table will not change its primary key, and that a uniqueness constraint will not be removed, but they explicitly do not guarantee that columns will not be added or reordered. Minor releases go further and do not guarantee against deletion, truncation or significant schema changes to tables, indexes, views and functions, though deprecation notices are meant to appear in execution logs first.
A second constraint is operational. The README says to always run Auth behind a TLS-capable proxy such as a load balancer, CDN or nginx. The binary does not terminate TLS for you. And the compatibility section states plainly that Auth is not meant to be used as a Go library, with no backward API guarantees regardless of which version number changes. If you were considering importing internal packages instead of running the server, that is the wrong tool.
Inherited Netlify features that may disappear
The README keeps a list of features inherited from the Netlify codebase that Supabase does not support and may remove without prior notice. The list is short and specific: multi-tenancy through the instances table and the GOTRUE_MULTI_INSTANCE_MODE configuration parameter, the system user with a zero UUID, super admin through the is_super_admin column, group information in JWTs via GOTRUE_JWT_ADMIN_GROUP_NAME and related fields, and JWT signing in its old form, where HS256 remains for compatibility while asymmetric keys are recommended.
This is the section to read before you commit to the project. Multi-tenancy in particular is the kind of feature that shapes an architecture. If you build a product where one Auth deployment serves several isolated tenants through the instances table, the README is telling you that foundation is unsupported and can be pulled out from under you. The README also notes that the list is not exhaustive and may change, which is honest but does not make planning easier.
On the signing side, the direction is clear enough to act on. Asymmetric keys with RS256 as the default let consumers validate tokens without the signing secret, and the README points to the signing keys and JWTs guides for the details. Migration away from HS256 is described as recommended rather than required, so an existing deployment using a shared secret is not broken, but new deployments have little reason to start there.
How supabase/auth differs from Clerk and Better Auth
The comparisons people reach for are Clerk and Better Auth, and the difference is not a feature checklist. It is where the identity data lives and who operates the service.
Clerk is a hosted identity product. You integrate an SDK, the user records stay with the vendor, and the operational burden of running an authentication server is theirs. supabase/auth is the opposite arrangement: the README expects you to run Postgres, run the binary, put a TLS proxy in front of it, and follow the releases and security advisories yourself. What you get in return is that the users table sits in your database next to the rest of your data, which is exactly what makes the PostgREST and Row Level Security integration possible. That integration is the reason to choose it, and it is also the reason it is a poor fit for a stack that has nothing to do with Supabase.
Better Auth is a library that lives inside your application process rather than a separate server. That means no second deployment, no migrations directory you are told not to touch, and no HTTP hop for every token check. It also means the identity logic ships with your application's release cycle, and there is no shared Postgres schema that a separate API service can read. If your reason for looking at supabase/auth is that you want JWTs that PostgREST can verify against Row Level Security policies, a library inside your app does not give you that. If your reason is simply that you want authentication, the library is the smaller commitment.
The comparison against the hosted Supabase Auth service is the one the README itself makes, and it is not flattering to self-hosting. The hosted option gets regular security updates. The self-hosted option gets a recommendation to set up a process for promptly updating to the latest version.
Maintenance cost, release cadence and the MIT licence
The last push to the repository was on 2026-09-25, three days before this writing, and the recent releases are all pre-release tags in the v2.198.0-rc line, with rc2.198.0-rc.21 published on 2026-09-22. That cadence tells you something practical: if you self-host, you are tracking a project that ships often, and the README asks you to follow both the Releases and Security Advisories sections so you can move promptly. Pinning a version and ignoring it is the failure mode the README warns about without naming it.
The versioning scheme is documented in more detail than most projects bother with, and the detail is useful when you plan upgrades. Patch releases guarantee backward compatibility for database objects, the REST API, JWT structure and configuration. Minor releases guarantee the same for the REST API, JWT structure and configuration, but not for database schema, which may see deletions or significant changes after a deprecation notice. Major releases guarantee nothing. Deprecation notices are meant to appear in execution logs for at least two major releases, or two weeks if releases are going out quickly, and compatibility holds while the notice is live. That gives you a concrete place to look: your logs, not the changelog alone.
The licence is MIT, which is permissive and places few obligations on how you deploy or modify the code. Nothing in the README imposes additional terms. What the licence does not do is transfer any responsibility for running the service, and the README is clear that security updates are your problem when you self-host. This is not legal advice; if the licence terms matter to your organisation, read the LICENSE file and get your own counsel.
Editorial conclusion
Adopt supabase/auth if you already run Supabase components yourself and need the token issuer inside your own network, and you accept that the migrations directory and the users schema are managed by the project rather than by you. Do not adopt it as a general purpose identity provider for an unrelated stack, and do not treat it as a Go library, since the README states there are no backward compatibility guarantees for that use. Before committing, verify three things: which version you are pinning, whether your deployment can run behind a TLS-capable proxy, and which of the inherited Netlify features, listed in the README, you currently depend on.
Frequently asked questions
Does Supabase provide auth?
Yes. Supabase Auth is a user management and authentication server written in Go, and the README lists issuing JWTs, user management, and sign in with email, password, magic link, phone number and external providers among the features it powers.
What is supabase/auth used for?
It issues JWTs and manages users, and it backs Row Level Security with PostgREST. The README also notes it powers sign in with email, password, magic link, phone number and external providers such as Google, Apple, Facebook and Discord.
How do I set up supabase/auth locally?
Create a .env.docker file following example.docker.env, then run make build and make dev. According to the README, docker ps should show two containers named auth-auth-1 and auth-postgres-1, and the health check endpoint at http://localhost:9999/health confirms the server is running.
What is Supabase Auth?
It is the authentication and user management server written in Go that powers Supabase features such as issuing JWTs and Row Level Security with PostgREST. The repository contains the server, not a client SDK.
How does supabase/auth issue JWTs?
The README states that Supabase Auth supports asymmetric keys, with RS256 as the default and ECC or Ed25519 optional, and that HS256 is still supported for compatibility while migrating to asymmetric keys is recommended for easier validation and rotation.
How do I add supabase/auth to a Next.js app?
The README does not document Next.js integration. The repository holds the Go authentication server and its REST endpoints, and the README points readers to the Supabase documentation site for guides.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/supabase-auth)