Skip to content

Run it locally

The provider on your own machine, in about five minutes. This is the page for reading the code, running the tests, or pointing an integration at something you control.

For the whole system — the provider plus both frontends, in containers — see Install it for your organization.

You need

  • Python 3.14+ and uv
  • Docker, for PostgreSQL and Redis

Start the backing services

Only the three stores run in Docker here. The provider itself runs on your machine, so you can restart it, attach a debugger, and read its logs directly.

# From the repository root
docker compose -f deploy/docker-compose.yml up -d postgres redis seaweedfs
Service Holds
PostgreSQL 18 with pgvector, on 5432 People, permissions, clients, tokens
Redis 8, on 6379 Sessions, pending sign-ins, the denylist, rate limits
SeaweedFS, on 8333 Profile photos, over the S3 API. Optional — leave IDEN_S3_ENDPOINT_URL empty to skip it

Naming the three services matters: up -d on its own would also start the provider and both frontends in containers, and their published ports would collide with the ones you are about to use.

Start the provider

cd provider

uv sync                              # install dependencies
cp .env.example .env                 # then read it — every setting is commented

uv run python -m scripts.gen_keys    # signing key + totp.key; the provider will not start without them
uv run alembic upgrade head          # create the schema
uv run python -m scripts.seed        # permissions, bootstrap admin, two clients

uv run provider                      # http://localhost:8000

Two of those deserve a note.

gen_keys writes one date-stamped PEM into provider/keys/, plus totp.key beside it. IDEN refuses to start without a signing key and will not invent one silently, because a key nobody can account for is not a key you want signing tokens. totp.key encrypts TOTP secrets at rest — the one credential IDEN cannot hash, since verifying a code means recomputing it. Back both up together.

seed prints two credentials, once:

Seeded 28 system scopes across 3 APIs.

  Bootstrap administrator — shown once, change it after first login
    email:    admin@localhost
    password: _qajl3wRjjx6QsuXMO9YY5tw

  Kiosk client secret — shown once, it is hashed in the database
    client_id:     kiosk
    client_secret: 7ZJbgK2um1y9QeliyysqElTJ-SUhC_8R8aXRygrmUgM

They are hashed on the way into the database and cannot be recovered. Losing them means seeding a fresh database — or, since this is development, running scripts.reset.

Check it worked

What URL
Interactive API docs http://localhost:8000/docs
OIDC discovery http://localhost:8000/.well-known/openid-configuration
Health http://localhost:8000/health

Discovery is the interesting one — it is the document every OIDC client library reads to configure itself, and it is generated from the live deployment rather than written by hand. scopes_supported is read from the database, so permissions you define appear there without a restart.

What the seed created

Detail
Two APIs admin and entity — IDEN's own, with all 25 of their permissions
Two roles administrator (everything) and member (self-service only)
One person The bootstrap administrator
dashboard A public client for the browser: PKCE, consent skipped, callbacks on ports 3000 and 5173
kiosk A confidential client for machine-to-machine access

The seed is idempotent — re-run it any time. It creates nothing structural; that is Alembic's job.

Sign in end to end

The fastest way to watch a real flow is the test suite, which drives one in-process:

uv run pytest tests/test_auth_code_flow.py -v

To drive it by hand, see Add a web application. To get the sign-in page and the dashboard in a browser, see Run the frontends.

Starting over

uv run python -m scripts.reset

Drops the schema, flushes Redis, re-migrates, and re-seeds — so you get a fresh bootstrap password. It refuses to run when IDEN_ENV=prod.

Common problems

connection refused on port 5432

PostgreSQL has not finished starting. docker compose -f deploy/docker-compose.yml ps should show it healthy.

NOAUTH Authentication required from Redis

The container asks for a password and the URL carries none. Both stores in deploy/docker-compose.yml default to iden, which is what .env.example already uses — so this means IDEN_REDIS_URL was edited, or IDEN_REDIS_PASSWORD in deploy/.env was set to something the provider does not know.

No schema found. Run alembic upgrade head first.

Exactly what it says — the seed refuses to half-fill an unmigrated database.

No signing keys in keys

scripts.gen_keys has not run, or IDEN_SIGNING_KEY_DIR does not point where it wrote.

Ports 8000, 4000 or 3000 are already in use

A previous docker compose up -d started the containerized provider or frontends. Stop them with docker compose -f deploy/docker-compose.yml stop provider auth-ui dashboard.

The sign-in round trip loses the session

Cookies are host-scoped. Whatever drives the flow must reach IDEN on the same host as IDEN_ISSUER, or the session cookie is never sent back — localhost and 127.0.0.1 are two different hosts to a browser.