# go-loose Go Loose is a multi-tenant API-key control plane for Go HTTP services. It gives operators a web console to register tenant applications, issue and revoke keys, import OpenAPI contracts, and inspect API metadata. Applications use the public `client` package as fail-closed middleware: requests without a valid key never reach the protected handler. | | | | --- | --- | | Module | github.com/danyel/go-loose · go 1.27.1 · 65 Go files | | Endpoints | 41 endpoints | | Components | 1 component directory | | Tests | 118 in 35 files | | Go lines | 11906 lines | > Everything between the generated markers is rewritten by every sync. Notes written outside the markers are kept. ## For Users ### What this application does Go Loose is a multi-tenant API-key control plane for Go HTTP services. It gives operators a web console to register tenant applications, issue and revoke keys, import OpenAPI contracts, and inspect API metadata. Applications use the public `client` package as fail-closed middleware: requests without a valid key never reach the protected handler. The project ships its own README at `README.md`, which is the long form of this page. The three audience tabs split the same facts three ways so you only read the part that concerns you. ### Reading this in go-doc Open the page and pick the tab that matches you: - **User** — you use the finished application. This section is all you need. - **Operator** — you run it. Configuration, ports and deployment notes are under that tab. - **Developer** — you integrate with it or change it. The API and layout tables are under that tab. The feedback panel stores a note per audience, tagged with your badge, so operators and developers can see which audience raised it. ### Where the original documentation lives This project already carries 9 Markdown documents. They stay in the project repository: this page points at them instead of copying them, so there is always exactly one copy of the truth. | Document | Size | | --- | --- | | `README.md` | 7729 bytes | | `docs/architecture.md` | 4958 bytes | | `docs/client-login.md` | 10667 bytes | | `docs/coding-standards.md` | 3213 bytes | | `docs/installation.md` | 6279 bytes | | `docs/integration.md` | 2163 bytes | | `docs/operations.md` | 4046 bytes | | `docs/password-authentication.md` | 2615 bytes | | `docs/roles.md` | 5608 bytes | --- ## For Operators ### Running it locally This project has no root Makefile, so the binary or container is run directly. ### Local containers The compose file defines these services: | Service | Image | Published ports | | --- | --- | --- | | postgres | `postgres:17-alpine` | internal only | | go-loose | built locally | internal only | | postgres | `postgres:17-alpine` | internal only | | go-loose | built locally | internal only | | postgres | `postgres:17-alpine` | internal only | | go-loose | built locally | internal only | ### Image `Dockerfile` builds from `golang:1.27.1-alpine`, `gcr.io/distroless/static-debian12:nonroot` in stages: build and exposes 8080. ### Configuration Every environment variable found in the source or in a `.env` file: | Variable | Example | Found in | | --- | --- | --- | | `GO_LOOSE_ADDR` | `:8080` | .env file | | `GO_LOOSE_ALLOWED_EMAIL_DOMAINS` | — | .env file | | `GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS` | `false` | .env file | | `GO_LOOSE_AUTH_DOMAIN` | `auth.dev` | .env file | | `GO_LOOSE_BASE_URL` | `https://auth.dev` | .env file | | `GO_LOOSE_BOOTSTRAP_APP` | `guess` | .env file | | `GO_LOOSE_BOOTSTRAP_TENANT` | `nmbs` | .env file | | `GO_LOOSE_DATABASE_URL` | `postgres://goloose:goloose@localhost:5432/goloose?sslmode=disable` | .env file | | `GO_LOOSE_DEV_LOGIN` | `false` | .env file | | `GO_LOOSE_DEV_USER` | `admin@local.test` | .env file | | `GO_LOOSE_LOCAL_ADMIN_EMAIL` | `admin@goloose.local` | .env file | | `GO_LOOSE_LOCAL_ADMIN_PASSWORD` | — | .env file | | `GO_LOOSE_LOCAL_LOGIN` | `true` | .env file | | `GO_LOOSE_OIDC_CLIENT_ID` | — | .env file | | `GO_LOOSE_OIDC_CLIENT_SECRET` | — | .env file | | `GO_LOOSE_OIDC_ISSUER` | — | .env file | | `GO_LOOSE_OIDC_REDIRECT_URL` | `https://auth.dev/auth/callback` | .env file | | `GO_LOOSE_SESSION_SECRET` | `replace-with-at-least-32-random-characters` | .env file | | `GO_LOOSE_THEME_BASE_URL` | — | source | ### Network surface Ports referenced across the project: `5433`, `8080`. ### Deployment artefacts Helm 1 chart found: - `deploy/helm/go-loose` ### Operations documentation that already exists Read these in place rather than duplicating them here: - `docs/installation.md` — First-run installation and demo data - `docs/operations.md` — Operations --- ## For Developers ### Module layout - go.mod — module github.com/danyel/go-loose, go 1.27.1, 5 direct and 9 indirect dependencies ### HTTP API Every route registration found in the source: | Method | Path | Handler | | --- | --- | --- | | `POST` | `/api/v1/applications` | `requireSession` | | `POST` | `/api/v1/applications/{id}/client-config` | `requireSession` | | `POST` | `/api/v1/authorize` | `authorize` | | `GET` | `/api/v1/avatars/{key}` | `avatar` | | `POST` | `/api/v1/contracts` | `requireSession` | | `GET` | `/api/v1/dashboard` | `requireSession` | | `POST` | `/api/v1/keys` | `requireSession` | | `POST` | `/api/v1/keys/{id}/revoke` | `requireSession` | | `GET` | `/api/v1/permissions` | `requireSession` | | `POST` | `/api/v1/permissions` | `requireSession` | | `DELETE` | `/api/v1/permissions/{name}` | `requireSession` | | `GET` | `/api/v1/profile` | `requireSession` | | `PUT` | `/api/v1/profile` | `requireSession` | | `GET` | `/api/v1/roles` | `requireSession` | | `POST` | `/api/v1/roles` | `requireSession` | | `DELETE` | `/api/v1/roles/{id}` | `requireSession` | | `PUT` | `/api/v1/roles/{id}` | `requireSession` | | `POST` | `/api/v1/tenants` | `requireSession` | | `POST` | `/api/v1/users` | `requireSession` | | `PUT` | `/api/v1/users/{id}/access` | `requireSession` | | `POST` | `/api/v1/users/{id}/approve` | `requireSession` | | `GET` | `/assets/{name}` | `asset` | | `GET` | `/auth/callback` | `authCallback` | | `GET` | `/auth/dev` | `authDev` | | `POST` | `/auth/logout` | `authLogout` | | `POST` | `/auth/password` | `passwordLogin` | | `GET` | `/auth/start` | `authStart` | | `GET` | `/client/login` | `clientLoginPage` | | `GET` | `/connect/authorize` | `clientAuthorize` | | `POST` | `/connect/logout` | `clientLogout` | | `POST` | `/connect/token` | `clientToken` | | `GET` | `/connect/userinfo` | `clientUserInfo` | | `GET` | `/docs` | `requireSession` | | `GET` | `/healthz` | `health` | | `GET` | `/install` | `installPage` | | `POST` | `/install` | `install` | | `GET` | `/login` | `loginPage` | | `GET` | `/openapi.json` | `requireSession` | | `GET` | `/profile` | `requireSession` | | `GET` | `/roles` | `requireSession` | | `GET` | `/{$}` | `requireSession` | ### Direct dependencies - `github.com/coreos/go-oidc/v3` v3.21.0 - `github.com/jackc/pgx/v5` v5.11.0 - `golang.org/x/crypto` v0.40.0 - `golang.org/x/oauth2` v0.37.0 - `gopkg.in/yaml.v3` v3.0.1 ### Directory map | Directory | Files | Lines | Likely purpose | | --- | --- | --- | --- | | `internal/` | 67 | 11684 | unimportable application internals | | `web/` | 15 | 827 | frontend assets | | `deploy/` | 11 | 59 | deployment manifests | | `docs/` | 8 | 0 | project documentation | | `client/` | 4 | 533 | frontend assets | | `cmd/` | 1 | 77 | binary entry points | ### Languages - **Go** — 65 files, 11906 lines - **Markdown** — 9 files, 863 lines - **JavaScript** — 4 files, 819 lines - **YAML** — 12 files, 626 lines - **JSON** — 2 files, 470 lines - **HTML** — 8 files, 426 lines - **SQL** — 8 files, 396 lines - **Templates** — 1 file, 59 lines - **CSS** — 1 file, 56 lines - **toml** — 1 file, 32 lines ### Developer documentation that already exists - `docs/architecture.md` — Architecture and decisions - `docs/coding-standards.md` — Coding standards - `docs/integration.md` — Integrating a Go API --- ## Related Documentation - [go-doc](go-doc.md) — The documentation platform itself - [go-bananas](go-bananas.md) — Design-token service (uses go-loose for auth) - [go-tell](go-tell.md) — Content CMS (uses go-loose for auth) - [go-places](go-places.md) — Location services (uses go-loose)