Releases: libraz/go-oidc-provider
Release list
v1.0.0
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.0Go 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.Baselinenames the OAuth 2.1 / RFC 9700 posture — PKCE on every authorization-code request, confidential clients included.profile.RequiredGrantsfailsop.Newwhen a declared profile names a grant the OP was not wired to serve, and the error names the option that activates it. Astartup.profileaudit 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'sgo.sumuntil you opt in.store.Transactionalis backed by a write buffer committing as oneTransactWriteItems; 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/passkeykitandop/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 behindinternal/.op.WithUserStorepoints claim reads at an embedder-owned user store while leaving every other substore of theWithStorebackend 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-implementedinteraction.Driver, TOTP enrolment, and a relying party completing the round-trip, on MySQL plus Redis under onedocker 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 implementstore.InteractionStoreCAS. Migration: add a realBeginTxand atomic expected-RawStateinteraction transitions; the SQL, in-memory, andexamples/26-byo-store-from-scratchimplementations are references. op.Newrejects a configuration where therefresh_tokengrant is enabled and cookie keys are set butStore.RefreshTokens()does not implementstore.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.GrantStorenow requiresListClientIDsBySubject, on a new optionalstore.GrantClientListerextension thatop.Newdemands of interactive configurations. Migration: implement a stable ascending, keyset-paginated client-ID query — do not delegate toListBySubjectand slice its result.- Account-lockout state moves to a versioned
AuthnLockoutStore.CompareAndSwapcontract, replacing the earlierStampLockextension. - Passkey stores must implement
store.PasskeyStore.UpdateAssertion, committing sign-count, clone-flag, and last-used as one atomic write instead of a whole-recordPutthat could rewind security state. - The token-endpoint transaction view (
Tx) gainsAccessTokens,OpaqueAccessTokens, andGrantRevocations, and the TOTP and email-OTP substores gainCompareAndSwap. op.Requirenames a step kind instead of carrying a step —Step StepbecomesKind StepKind. Migration: replaceop.Require{Step: s}withop.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'sNotAfteris a hard retirement deadline — the OP refuses to decrypt for thatkidand drops the public half from the published JWKS. passkey.ConfigrejectsAAGUIDAllowlistpaired with any conveyance other thandirect. 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
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.5Go 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_jwtkey selection hardened against DoS amplification. The assertion verification key is selected by JWSkid(RFC 7515 §4.1.4), and trial verifications are capped whether or not akidis present.kiduniqueness is unenforced, so a client serving many keys — including same-kid, same-algduplicates — can no longer force one signature verify per key.- DPoP scheme enforced at
/userinfo. A DPoP-bound access token presented under theBearerscheme is rejected; RFC 9449 §7.1 requires theDPoPscheme for sender-constrained tokens. - Orphaned opaque access tokens revoked on failed mints. Every post-mint
server_errorpath (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.5across the root module, the storage-adapter sub-modules, and CI, picking up thecrypto/tlsfix for GO-2026-5856 (Encrypted Client Hello privacy leak); the previously pinnedgo1.26.4is affected. - New
op.WithPARLifetimeoption to size therequest_uripresentation 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, andmitchellh/mapstructurereplaced by the maintainedgo-viper/mapstructure/v2fork. - A runnable durable SQL-backed
store.TOTPStoreexample (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 omitscode_challengereceivesinvalid_requestat 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
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.4Go 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_jwtclients with ajwks_uri. An assertion signed with a key whosekidis 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-kidreplay 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_tokennever 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
cnfbinding and a thumbprint mismatch is rejected (ErrCertSourceConflict) rather than silently binding the proxy's own certificate. MinAALstep-up enforcement on the legacy authenticator chain, plus account-chooser re-entry seedingacr/amr/ auth time from the selected session.- New
op.WithDeviceCodeExpiry/op.WithDeviceCodePollIntervaloptions.
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 construction —
op.Newfails 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
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.3Go 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_detailsis validated against theop.WithAuthorizationDetailTypesregistry, persisted on the grant, and echoed on JWT access tokens and introspection; grants can be queried and revoked viaop.WithGrantManagement; and each registered resource advertises its protecting authorization servers viaop.WithProtectedResources. - Device-code and CIBA now run on the SQL adapter (mysql / postgres / sqlite), so
WithDeviceCodeGrant/WithCIBAno 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-tokenid/parent_idare 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.StepUpChallengebuilds an RFC 9470 step-upWWW-Authenticate: Bearerchallenge string for an embedder's resource server to return.go-josebumped to v4.1.4, fixing a JWE-decryption panic (GO-2026-4945).
Breaking changes
- Client verification keys (
client_assertionand JAR request objects) are held to the OP key-shape floor (RSA ≥ 2048 bits; EC curve pinned to the declaredalg); sub-floor keys are rejected asErrSigInvalid. RefreshTokenStore.Consumeis now an atomic compare-and-set returning the consumed record on replay;store.RefreshTokencarries new authentication-context fields and hashedid/parent_id(newoidc_refresh_tokenscolumns; legacy unhashed table shapes are rejected).- One-time auth factors (
emailotpConsume /totpAccept /recoveryConsume) 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_methodset at construction — a FAPI profile (FAPI2Baseline/FAPI2MessageSigning/FAPICIBA) rejectsnone/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
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.2Go 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.Revokerevokes every access token issued from the revokeddevice_codeviaAccessTokenRegistry.RevokeByGrantwhen the newdevicecodekit.Deps.AccessTokensregistry 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
typfollows RFC 9101 §10.8 (theoauth-authz-req+jwtmedia type is RECOMMENDED, matched case-insensitively per RFC 2045 §5.1; an absenttypis accepted) andaudfollows 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-referrerand CSPform-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 ofIssueRefreshToken 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
- Documentation: https://go-oidc-provider.libraz.net
- Go reference: https://pkg.go.dev/github.com/libraz/go-oidc-provider/op
- Examples: https://github.com/libraz/go-oidc-provider/tree/v0.9.2/examples
- Security policy: https://github.com/libraz/go-oidc-provider/blob/v0.9.2/SECURITY.md
v0.9.1
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.1Go 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-authorizeendpoint, theurn:openid:params:grant-type:cibatoken grant, and a newop.CIBARequestStoresubstore. Push and ping delivery modes are deferred to v2+. - RFC 8693 token-exchange grant_type via
op.RegisterTokenExchangewith 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 newop/devicecodekitsub-package for embedder-sideuser_codeverification with a per-record brute-force lockout. - OIDC Core §8 pairwise subject derivation (
op.WithPairwiseSubject(salt)/op.WithSubjectGenerator(...)) with hardenedsector_identifier_uriresolution and mid-life-strategy switching rejected atop.New. - RFC 7516 JWE encryption for inbound JAR / PAR request objects and outbound
id_token, JWT-shapeuserinfo, JARM authorization responses, and RFC 9701 introspection responses, advertised via the matching*_encryption_alg_values_supporteddiscovery fields. - Stable custom-grant dispatcher:
op.WithCustomGrant(...)graduates out of its experimental marker, with a documented cnf-binding contract and aBoundAccessTokenhelper for DPoP / mTLS-bound handler responses. profile.FAPICIBAgraduates 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+ theconsent.granted.first_partyaudit event), a profile-levelRequiredAnyOfauto-default that letsWithProfile(FAPI2Baseline)activate DPoP with no further wiring, automatic CORS allowlisting of static-client redirect URI origins, locale-resolver fallback forui_locales_supported, and aWithAllowInsecureBackchannelLogoutForDevdev opt-in for loopback http back-channel logout.
Breaking changes
op.WithInteractionis renamed toop.WithInteractionDriver.- The single-key wrappers
op.WithCookieKeyandop.WithMFAEncryptionKeyare removed in favour of the keyset forms (op.WithCookieKeys,op.WithMFAEncryptionKeys). - The no-op
op.WithPasskeyAttestationstub 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
- Documentation: https://go-oidc-provider.libraz.net
- Go reference: https://pkg.go.dev/github.com/libraz/go-oidc-provider/op
- Examples: https://github.com/libraz/go-oidc-provider/tree/v0.9.1/examples
- Security policy: https://github.com/libraz/go-oidc-provider/blob/v0.9.1/SECURITY.md
v0.9.0
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.0Go 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.0Quickstart
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 lockThe 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
- Documentation: https://go-oidc-provider.libraz.net
- Go reference: https://pkg.go.dev/github.com/libraz/go-oidc-provider/op
- Examples: https://github.com/libraz/go-oidc-provider/tree/v0.9.0/examples
- Security policy: https://github.com/libraz/go-oidc-provider/blob/v0.9.0/SECURITY.md
op/storeadapter/sql/v0.9.0
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.0Released alongside the main module's v0.9.0 initial public release.
op/storeadapter/redis/v0.9.0
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.0Released alongside the main module's v0.9.0 initial public release.