Skip to content

Releases: libraz/go-oidc-provider

v1.0.0

Choose a tag to compare

@libraz libraz released this 27 Jul 00:56

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v1.0.0
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v1.0.0
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v1.0.0
go get github.com/libraz/go-oidc-provider/op/storeadapter/dynamodb@v1.0.0

Go 1.26.5+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

The first release under strict Semantic Versioning. From here the public op surface changes only on a major version, with one stated exception: symbols carrying an experimental stability marker, which are listed in api/experimental.txt and gated mechanically so the exemption cannot grow silently.

Beyond that, this is a hardening and durability pass across the token endpoint, the storage layer, and construction-time validation. The authorization-code, refresh, CIBA, and device-code flows stage their fallible work behind transactions and single-use compare-and-swaps, so an approved ceremony survives a signing or persistence fault; back-channel logout fans out through keyset-paginated grant lookups; and op.New rejects a far wider class of misconfiguration up front. No new protocol surface.

  • The security posture is something a deployment declares, not something it inherits by omission. profile.Baseline names the OAuth 2.1 / RFC 9700 posture — PKCE on every authorization-code request, confidential clients included. profile.RequiredGrants fails op.New when a declared profile names a grant the OP was not wired to serve, and the error names the option that activates it. A startup.profile audit event reports the resolved policy — PKCE / PAR / nonce mandates, sender constraint, token TTLs and formats, signing algorithm — once per successful construction.
  • op/storeadapter/dynamodb, a third storage adapter, published as its own module so the AWS SDK stays out of the main module's go.sum until you opt in. store.Transactional is backed by a write buffer committing as one TransactWriteItems; expiry is enforced on read against the injected clock rather than trusting DynamoDB's asynchronous TTL sweep.
  • The SQL adapter implements every authentication-factor substore — TOTP, passkey, recovery code, email OTP, and the cross-factor lockout counter — with DDL for SQLite, MySQL, and PostgreSQL. They stay off store.Store, so a deployment enabling no second factor need not provision their tables.
  • op/passkeykit and op/recoverykit, the enrolment halves of passkeys and recovery codes. Both factors could previously be demanded by a login flow that no embedder could enrol a user in, because the registration ceremony and the code parameters lived behind internal/.
  • op.WithUserStore points claim reads at an embedder-owned user store while leaving every other substore of the WithStore backend untouched — replacing a hand-written wrapper that silently dropped the backend's optional capabilities.
  • Signing is ES256 only, and that is now a stated permanent policy for the 1.x line rather than an unfilled gap. Deployments needing RS256 or PS256 should not adopt this release.
  • sample/, a reference application covering the arc the single-concept examples skip: application-owned registration, Argon2id password storage, an embedder-implemented interaction.Driver, TOTP enrolment, and a relying party completing the round-trip, on MySQL plus Redis under one docker compose up.

Breaking changes

Several store-interface and construction changes are breaking for custom store implementations. They are the last such changes that can land outside a major version.

  • Authorization-code stores must implement store.Transactional, and their interaction substore must implement store.InteractionStoreCAS. Migration: add a real BeginTx and atomic expected-RawState interaction transitions; the SQL, in-memory, and examples/26-byo-store-from-scratch implementations are references.
  • op.New rejects a configuration where the refresh_token grant is enabled and cookie keys are set but Store.RefreshTokens() does not implement store.RefreshRetryResponseStore. Such a setup previously passed construction and then failed every rotation at request time. Migration: implement the extension; the bundled adapters already do.
  • store.GrantStore now requires ListClientIDsBySubject, on a new optional store.GrantClientLister extension that op.New demands of interactive configurations. Migration: implement a stable ascending, keyset-paginated client-ID query — do not delegate to ListBySubject and slice its result.
  • Account-lockout state moves to a versioned AuthnLockoutStore.CompareAndSwap contract, replacing the earlier StampLock extension.
  • Passkey stores must implement store.PasskeyStore.UpdateAssertion, committing sign-count, clone-flag, and last-used as one atomic write instead of a whole-record Put that could rewind security state.
  • The token-endpoint transaction view (Tx) gains AccessTokens, OpaqueAccessTokens, and GrantRevocations, and the TOTP and email-OTP substores gain CompareAndSwap.
  • op.Require names a step kind instead of carrying a stepStep Step becomes Kind StepKind. Migration: replace op.Require{Step: s} with op.Require{Kind: s.Kind()} and declare the step on the flow.
  • Trusted-proxy mTLS certificate headers accept exactly one field containing one PEM block. Migration: configure the TLS terminator to strip the inbound header and forward only the verified client leaf.
  • An EncryptionKey's NotAfter is a hard retirement deadline — the OP refuses to decrypt for that kid and drops the public half from the published JWKS.
  • passkey.Config rejects AAGUIDAllowlist paired with any conveyance other than direct. The allowlist previously compared an unauthenticated AAGUID, so a software authenticator could register by naming an approved model.
  • Removed profile.IGovHigh. Migration: none — no configuration that named it could ever boot.

See CHANGELOG.md for the full Added / Changed / Removed / Fixed / Security lists with per-change migration notes.

Status

Strict Semantic Versioning from this release onward; the experimental exemption is limited to the symbols listed in api/experimental.txt. This is a personal hobby project. It is regressed against the OpenID Foundation conformance suite on every release but carries no formal certification; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

v0.9.5

Choose a tag to compare

@libraz libraz released this 12 Jul 18:02

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.5
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.5
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.5

Go 1.26.5+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

A security-hardening release: no new protocol surface, but a broad sweep of abuse-resistance and correctness fixes plus a dependency and toolchain refresh.

  • PKCE is now mandatory for public and native clients (see Breaking changes).
  • private_key_jwt key selection hardened against DoS amplification. The assertion verification key is selected by JWS kid (RFC 7515 §4.1.4), and trial verifications are capped whether or not a kid is present. kid uniqueness is unenforced, so a client serving many keys — including same-kid, same-alg duplicates — can no longer force one signature verify per key.
  • DPoP scheme enforced at /userinfo. A DPoP-bound access token presented under the Bearer scheme is rejected; RFC 9449 §7.1 requires the DPoP scheme for sender-constrained tokens.
  • Orphaned opaque access tokens revoked on failed mints. Every post-mint server_error path (id_token mint/encrypt failure, refresh-issuance failure, grant-tombstone refusal) now revokes the persisted access-token row, so no still-valid token lingers until TTL or GC.
  • Toolchain pinned to go1.26.5 across the root module, the storage-adapter sub-modules, and CI, picking up the crypto/tls fix for GO-2026-5856 (Encrypted Client Hello privacy leak); the previously pinned go1.26.4 is affected.
  • New op.WithPARLifetime option to size the request_uri presentation window (RFC 9126 §2.2).
  • Dependency refresh: go-webauthn/webauthn → v0.17.4, golang-jwt/jwt/v5 → v5.3.1, golang.org/x/crypto → v0.54, the SQL drivers, and mitchellh/mapstructure replaced by the maintained go-viper/mapstructure/v2 fork.
  • A runnable durable SQL-backed store.TOTPStore example (examples/27-durable-mfa-store) as a copy-and-adapt template for embedder-owned authentication-factor persistence.

Breaking changes

  • PKCE (code_challenge) is now mandatory for public and native clients at /authorize, independent of the active profile. A public or native client that omits code_challenge receives invalid_request at the authorization endpoint and no authorization code is issued. Migration: register public and native clients with PKCE (S256). The token-endpoint PKCE downgrade guard remains as defense in depth.

See CHANGELOG.md for the full Added / Changed / Fixed / Security lists with per-change migration notes.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

v0.9.4

Choose a tag to compare

@libraz libraz released this 02 Jul 19:35

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.4
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.4
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.4

Go 1.26+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

A security-hardening release: no new protocol surface, but a broad sweep of correctness and abuse-resistance fixes.

  • RP key rotation for private_key_jwt clients with a jwks_uri. An assertion signed with a key whose kid is absent from the OP's cached keyset — the rotation signal — now triggers a single throttled, cache-bypassing refetch and retry, instead of rejecting until the cache TTL lapses. The per-URL throttle prevents random-kid replay from amplifying into unbounded outbound fetches.
  • Token-exchange down-scope invariant (RFC 8693). The policy decision is re-verified after application: granted scope must stay a subset of the requested (subject-token-bounded) scope and granted audience a subset of the requested audience, closing a privilege-escalation path where a policy bug could mint tokens for scopes/audiences the subject_token never carried.
  • Refresh replay-revocation race closed. A rotation save can no longer outrun a concurrent chain revocation (SQL re-checks the parent under a row lock in-transaction; in-memory checks parent-alive inside the insert critical section), so a replayed stolen refresh token's descendant is reliably revoked.
  • mTLS token-binding collapse fixed. With a client-cert forwarding header and a trusted proxy peer, the forwarded certificate is authoritative for the cnf binding and a thumbprint mismatch is rejected (ErrCertSourceConflict) rather than silently binding the proxy's own certificate.
  • MinAAL step-up enforcement on the legacy authenticator chain, plus account-chooser re-entry seeding acr / amr / auth time from the selected session.
  • New op.WithDeviceCodeExpiry / op.WithDeviceCodePollInterval options.

Breaking changes

  • The device-code lifetime is decoupled from the access-token TTL. It now defaults to the device-grant defaults and is set via WithDeviceCodeExpiry / WithDeviceCodePollInterval. Migration: deployments that sized the device-code window via a custom access-token TTL must set the new options explicitly.
  • A non-zero refresh grace period is rejected under a FAPI 2.0 profile at constructionop.New fails fast instead of allowing a refresh-token replay window the FAPI 2.0 contract forbids. Migration: remove the refresh grace-period option from FAPI-profiled providers.

See CHANGELOG.md for the full Added / Changed / Fixed / Security lists with per-change migration notes.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

v0.9.3

Choose a tag to compare

@libraz libraz released this 14 Jun 19:08

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.3
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.3
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.3

Go 1.25+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

  • RFC 9396 Rich Authorization Requests, OAuth 2.0 Grant Management, and RFC 9728 protected-resource metadata land together: authorization_details is validated against the op.WithAuthorizationDetailTypes registry, persisted on the grant, and echoed on JWT access tokens and introspection; grants can be queried and revoked via op.WithGrantManagement; and each registered resource advertises its protecting authorization servers via op.WithProtectedResources.
  • Device-code and CIBA now run on the SQL adapter (mysql / postgres / sqlite), so WithDeviceCodeGrant / WithCIBA no longer require the inmem reference store.
  • Refresh-token rotation preserves the original authentication context (auth_time, acr, amr, authorization_details, …) so refresh-derived id_tokens and JWT access tokens reproduce it faithfully; refresh-token id / parent_id are now hashed at rest with constant-time lookups.
  • Auth-factor single-use is atomic — email-OTP / TOTP / recovery codes can no longer be replayed under concurrency — a cross-factor account-lockout race is closed, and terminal factor failures now return HTTP 400.
  • op.StepUpChallenge builds an RFC 9470 step-up WWW-Authenticate: Bearer challenge string for an embedder's resource server to return.
  • go-jose bumped to v4.1.4, fixing a JWE-decryption panic (GO-2026-4945).

Breaking changes

  • Client verification keys (client_assertion and JAR request objects) are held to the OP key-shape floor (RSA ≥ 2048 bits; EC curve pinned to the declared alg); sub-floor keys are rejected as ErrSigInvalid.
  • RefreshTokenStore.Consume is now an atomic compare-and-set returning the consumed record on replay; store.RefreshToken carries new authentication-context fields and hashed id / parent_id (new oidc_refresh_tokens columns; legacy unhashed table shapes are rejected).
  • One-time auth factors (emailotp Consume / totp Accept / recovery Consume) are single-use via atomic CAS, and terminal factor failures render HTTP 400 instead of 500.
  • Static client seeds are validated against the active profile's allowed token_endpoint_auth_method set at construction — a FAPI profile (FAPI2Baseline / FAPI2MessageSigning / FAPICIBA) rejects none / client_secret_* clients.

See CHANGELOG.md for the full Added / Changed / Fixed / Security lists with per-change migration notes.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

v0.9.2

Choose a tag to compare

@libraz libraz released this 24 May 06:21

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.2
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.2
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.2

Go 1.25+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

  • Refresh tokens for custom grants and RFC 8693 token-exchange are now wired into the OP's own refresh-token lineage. A handler sets CustomGrantResponse.IssueRefreshToken (or a token-exchange policy opts in); the OP — not the handler — mints and persists the credential (RFC 6749 §6), sharing the access token's grant identity so it rides the standard rotation, single-use replay-cascade (RFC 9700 §2.2.2), and DPoP / mTLS cnf-binding machinery.
  • Device-authorization revocation now cascades inside the library: devicecodekit.Revoke revokes every access token issued from the revoked device_code via AccessTokenRegistry.RevokeByGrant when the new devicecodekit.Deps.AccessTokens registry is wired.
  • Broad security-hardening sweep across DPoP, JAR / JARM, JOSE, mTLS, refresh rotation, client authentication, i18n input, metrics cardinality, and the authorize / userinfo / introspection / end-session endpoints.
  • Request-object and JARM handling aligned with the specs: request-object typ follows RFC 9101 §10.8 (the oauth-authz-req+jwt media type is RECOMMENDED, matched case-insensitively per RFC 2045 §5.1; an absent typ is accepted) and aud follows RFC 9101 §6.1 (the issuer must be present, not the sole audience), so conformant relying parties interoperate at PAR and the backchannel endpoint.
  • Default-driver browser login unblocked: the interaction HTML pages no longer emit the Referrer-Policy: no-referrer and CSP form-action 'self' headers that broke a real browser's credential POST and post-consent redirect.

Breaking changes

  • op.CustomGrantResponse.RefreshToken string (a reserved field that was always rejected) is removed in favour of IssueRefreshToken bool. The string field let a handler supply a refresh-token value, which contradicts the RFC 6749 §6 model where the authorization server owns the credential; the flag lets the handler signal intent while the OP retains ownership of the value and its lineage. No existing call site loses behaviour because the string field never produced a usable refresh token.

See CHANGELOG.md for the full Added / Changed / Fixed / Removed lists, including every audit event, security hardening, and substore contract change in this release.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

Links

v0.9.1

Choose a tag to compare

@libraz libraz released this 07 May 13:11

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.1
go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.1
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.1

Go 1.25+. The main module and the storage-adapter sub-modules share the same release tag.

Highlights

  • CIBA poll mode (OpenID Connect Client-Initiated Backchannel Authentication Core 1.0): /oidc/bc-authorize endpoint, the urn:openid:params:grant-type:ciba token grant, and a new op.CIBARequestStore substore. Push and ping delivery modes are deferred to v2+.
  • RFC 8693 token-exchange grant_type via op.RegisterTokenExchange with audience normalisation (RFC 8707 §2), act-claim chain assembly, and DPoP / mTLS cnf rebinding on the issued token.
  • RFC 8628 device-authorization grant via op.WithDeviceCode(...), plus the new op/devicecodekit sub-package for embedder-side user_code verification with a per-record brute-force lockout.
  • OIDC Core §8 pairwise subject derivation (op.WithPairwiseSubject(salt) / op.WithSubjectGenerator(...)) with hardened sector_identifier_uri resolution and mid-life-strategy switching rejected at op.New.
  • RFC 7516 JWE encryption for inbound JAR / PAR request objects and outbound id_token, JWT-shape userinfo, JARM authorization responses, and RFC 9701 introspection responses, advertised via the matching *_encryption_alg_values_supported discovery fields.
  • Stable custom-grant dispatcher: op.WithCustomGrant(...) graduates out of its experimental marker, with a documented cnf-binding contract and a BoundAccessToken helper for DPoP / mTLS-bound handler responses.
  • profile.FAPICIBA graduates from placeholder to enforced (JAR + DPoP-or-MTLS, 10-minute access-token cap, FAPI 2.0 client-authentication set, mandatory access-token revocation).
  • New first-party auto-consent path (op.WithFirstPartyClients + the consent.granted.first_party audit event), a profile-level RequiredAnyOf auto-default that lets WithProfile(FAPI2Baseline) activate DPoP with no further wiring, automatic CORS allowlisting of static-client redirect URI origins, locale-resolver fallback for ui_locales_supported, and a WithAllowInsecureBackchannelLogoutForDev dev opt-in for loopback http back-channel logout.

Breaking changes

  • op.WithInteraction is renamed to op.WithInteractionDriver.
  • The single-key wrappers op.WithCookieKey and op.WithMFAEncryptionKey are removed in favour of the keyset forms (op.WithCookieKeys, op.WithMFAEncryptionKeys).
  • The no-op op.WithPasskeyAttestation stub is removed (it never gated anything; verification belongs in the embedder's WebAuthn library).

See CHANGELOG.md for the full Added / Changed / Fixed / Removed lists, including every audit event, security hardening, and substore contract change in this release.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

Links

v0.9.0

Choose a tag to compare

@libraz libraz released this 01 May 18:40

OpenID Connect Provider (Authorization Server) library for Go. op.New(...) returns a standard http.Handler you mount on net/http, chi, gin, or any router — no framework lock-in, no global state. Targets FAPI 2.0 Baseline / Message Signing.

Install

go get github.com/libraz/go-oidc-provider/op@v0.9.0

Go 1.25+. Storage adapters ship as sub-modules so their driver dependencies stay out of your go.sum until you opt in:

go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.0
go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.0

Quickstart

handler, err := op.New(
    op.WithIssuer("https://idp.example.com"),
    op.WithStore(inmem.New()),
    op.WithKeyset(op.Keyset{{KeyID: "k1", Signer: priv}}),
    op.WithCookieKey(cookieKey),
)
if err != nil {
    log.Fatal(err)
}
log.Fatal(http.ListenAndServe(":8080", handler))

For FAPI 2.0 Baseline in a single switch:

op.WithProfile(profile.FAPI2Baseline) // PAR + JAR + DPoP, ES256, alg lock

The constructor refuses to start if the declared profile conflicts with the rest of the options.

Status

Pre-v1.0 — the public API may change in any minor release until v1.0.0. This is a personal hobby project; see the README and SECURITY.md for scope, threat model, and the "what this library is — and is not" boundary.

Links

op/storeadapter/sql/v0.9.0

Choose a tag to compare

@libraz libraz released this 01 May 18:40

SQL storage adapter for go-oidc-provider — MySQL, PostgreSQL, and SQLite via database/sql. Driver dependencies live in this sub-module so the main library's go.sum stays minimal.

go get github.com/libraz/go-oidc-provider/op/storeadapter/sql@v0.9.0

Released alongside the main module's v0.9.0 initial public release.

op/storeadapter/redis/v0.9.0

Choose a tag to compare

Redis storage adapter for go-oidc-provider — backs the volatile substores (Sessions, Interactions, ConsumedJTIs). Driver dependencies live in this sub-module so the main library's go.sum stays minimal.

go get github.com/libraz/go-oidc-provider/op/storeadapter/redis@v0.9.0

Released alongside the main module's v0.9.0 initial public release.