Self-hosted identity for local and pre-prod environments.
Spin up OIDC/OAuth2 + SAML in minutes with a Go + Fiber + Postgres stack.
GoIdP is a developer-first Identity Provider built for teams that need realistic authentication flows without the enterprise setup tax. Use it to test:
- OIDC Authorization Code + PKCE flows
- OAuth2 password grant in controlled environments
- SAML SP-initiated HTTP-POST SSO
- Session-based browser login experiences
- Fast to start: one command with Docker Compose
- Protocol complete for local dev: OIDC, OAuth2, SAML in one service
- Deterministic testing: seeded users, clients, and SP entries
- Simple to operate: Postgres-backed sessions + built-in migrations
- Go-native stack: Fiber HTTP server and straightforward codebase
- Authorization endpoint:
GET /authorize - Token endpoint:
POST /token(authorization_code,password) - Discovery:
GET /.well-known/openid-configuration - JWKS:
GET /jwks - User profile:
GET /userinfo
- IdP metadata:
GET /saml/metadata - SSO entrypoint:
POST /saml/sso - Login-resume endpoint:
GET /saml/sso?pending_saml_id=...
- Branded login UI at
GET /login - Postgres-backed session store
HttpOnlycookie withSameSite=Lax
Run the full local stack:
docker compose up --buildThis starts:
db(Postgres 16)idp-bootstrap(migrations + seed data)idp(GoIdP server) GoIdP will be available athttp://localhost:8080.
- User:
alice/password123 - OAuth2/OIDC client:
client_id:demo-client- public client (no secret)
- redirect URI:
http://localhost:8081/callback - grant types:
authorization_code,password - scopes:
openid
- SAML SP:
- issuer:
http://sp.example/metadata - ACS URL:
http://sp.example/acs - audience URI:
http://sp.example/audience
- issuer:
curl -sS http://localhost:8080/healthz
curl -sS http://localhost:8080/.well-known/openid-configuration
curl -sS http://localhost:8080/jwks
curl -sS http://localhost:8080/saml/metadataStop services:
docker compose downReset DB and key volumes:
docker compose down -vGoIdP supports:
config.yml/config.yamlat repo root- environment variables (env overrides YAML) Example:
database_url: 'postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable'
public_issuer_url: 'http://localhost:8080'
listen_addr: ':8080'
cookie_secure: false
session_ttl: '24h'
jwt_access_ttl: '15m'
jwt_id_ttl: '15m'
dev_keys_dir: './dev-keys'
migrations_dir: './migrations'Required:
DATABASE_URLPUBLIC_ISSUER_URL
Optional:
LISTEN_ADDR(default:8080)COOKIE_SECURE(defaultfalse)SESSION_TTL(default24h)JWT_ACCESS_TTL(default15m)JWT_ID_TTL(default15m)DEV_KEYS_DIR(default./dev-keys)MIGRATIONS_DIR(default./migrations)
- Start Postgres
- Set
DATABASE_URLandPUBLIC_ISSUER_URL - Run:
go run ./cmd/idpMigrations run automatically on startup.
idpctl manages users, OAuth clients, and SAML SP registrations.
Install:
go install ./cmd/idpctlEnsure Go bin is on PATH:
export PATH="$(go env GOPATH)/bin:$PATH"go run ./cmd/idpctl user add \
--username alice \
--password password123 \
--display-name "Alice Example" \
--email alice@example.comPublic client:
go run ./cmd/idpctl client add \
--public \
--client-id demo-client \
--redirect-uri "http://localhost:8081/callback" \
--grant-types "authorization_code,password" \
--scopes "openid"Confidential client:
go run ./cmd/idpctl client add \
--client-id my-app \
--redirect-uri "http://localhost:8081/callback" \
--grant-types "authorization_code,password" \
--scopes "openid"go run ./cmd/idpctl samlsp add \
--issuer "http://sp.example/metadata" \
--acs-url "http://sp.example/acs" \
--audience-uri "http://sp.example/audience" \
--name-id-format "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"Typical flow:
- Register your callback URI in GoIdP
- Redirect users to
GET /authorizewithcode_challengeandnonce - Handle callback with
code+state - Exchange code at
POST /tokenwithcode_verifierMinimum authorize params:
response_type=codeclient_idredirect_uriscope(openidfor ID token)statecode_challengecode_challenge_method=S256nonce(required withopenid)
- Register SP issuer + ACS URL in GoIdP
- SP sends
SAMLRequesttoPOST /saml/sso - If user is not logged in, GoIdP redirects to
/login - After login, GoIdP returns auto-submit HTML with
SAMLResponseto ACS
Health:
GET /healthzLogin:GET /loginPOST /loginOIDC/OAuth2:GET /.well-known/openid-configurationGET /jwksGET /authorizePOST /token
- OIDC signing keys are persisted under
DEV_KEYS_DIR - Key metadata is stored in Postgres (
signing_keys_meta) - Migrations run via both
idpandidpctl - Integration tests are under
internal/integration/Run tests:
go test ./... -run TestOIDC_AuthorizationCode_PKCE -v
go test ./... -run TestSAML_SPInitiated_POST -v