Repository: zitadel/oidc (go)

Issue:
Switch to `log/slog`
### Preflight Checklist

- [X] I could not find a solution in the existing issues, docs, nor discussions
- [ ] I have joined the [ZITADEL chat](https://zitadel.com/chat)

### Describe your problem

While `log/slog` and `golang.org/x/exp/slog` having the same API, they could not used together.

According to the README, if `zitadel/oidc` switches to go 1.22, it should be safe to use `log/slog`, since it's supported since go 1.21.



### Describe your ideal solution

I'm able to pass the `log/slog` logger to `zitadel/oidc` library calls.

### Version

3.12.0

### Environment

Self-hosted

### Additional Context

_No response_

Pull request:
feat: go 1.22 and slog migration
This change adds Go 1.22 as a build target and drops support for Go 1.20 and older. The golang.org/x/exp/slog import is migrated to log/slog.

Slog has been part of the Go standard library since Go 1.21. Therefore we are dropping support for older Go versions. This is in line of our support policy of "the latest two Go versions".

Depends on https://github.com/zitadel/logging/pull/21
Closes #549

### Definition of Ready

- [x] I am happy with the code
- [x] Short description of the feature/issue is added in the pr description
- [x] PR is linked to the corresponding user story
- [x] Acceptance criteria are met
- [x] All open todos and follow ups are defined in a new ticket and justified
- [x] Deviations from the acceptance criteria and design are agreed with the PO and documented.
- [x] No debug or dead code
- [x] My code has no repetitions
- [x] Critical parts are tested automatically
- [x] Where possible E2E tests are implemented
- [x] Documentation/examples are up-to-date
- [x] All non-functional requirements are met
- [ ] Functionality of the acceptance criteria is checked manually on the dev system.



Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 12b9007..a4a8f87 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,7 +18,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: ['1.19', '1.20', '1.21']
+        go: ['1.21', '1.22']
     name: Go ${{ matrix.go }} test
     steps:
       - uses: actions/checkout@v4
diff --git a/README.md b/README.md
index 7f1a610..72ae8d4 100644
--- a/README.md
+++ b/README.md
@@ -115,10 +115,9 @@ Versions that also build are marked with :warning:.
 
 | Version | Supported          |
 | ------- | ------------------ |
-| <1.19   | :x:                |
-| 1.19    | :warning:          |
-| 1.20    | :white_check_mark: |
+| <1.21   | :x:                |
 | 1.21    | :white_check_mark: |
+| 1.22    | :white_check_mark: |
 
 ## Why another library
 
diff --git a/example/client/app/app.go b/example/client/app/app.go
index 0e339f4..a779169 100644
--- a/example/client/app/app.go
+++ b/example/client/app/app.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"log/slog"
 	"net/http"
 	"os"
 	"strings"
@@ -12,7 +13,6 @@ import (
 
 	"github.com/google/uuid"
 	"github.com/sirupsen/logrus"
-	"golang.org/x/exp/slog"
 
 	"github.com/zitadel/logging"
 	"github.com/zitadel/oidc/v3/pkg/client/rp"
diff --git a/example/server/exampleop/op.go b/example/server/exampleop/op.go
index baa2662..893628e 100644
--- a/example/server/exampleop/op.go
+++ b/example/server/exampleop/op.go
@@ -3,13 +3,13 @@ package exampleop
 import (
 	"crypto/sha256"
 	"log"
+	"log/slog"
 	"net/http"
 	"sync/atomic"
 	"time"
 
 	"github.com/go-chi/chi/v5"
 	"github.com/zitadel/logging"
-	"golang.org/x/exp/slog"
 	"golang.org/x/text/language"
 
 	"github.com/zitadel/oidc/v3/example/server/storage"
diff --git a/example/server/main.go b/example/server/main.go
index 38057fb..a2ad190 100644
--- a/example/server/main.go
+++ b/example/server/main.go
@@ -2,12 +2,12 @@ package main
 
 import (
 	"fmt"
+	"log/slog"
 	"net/http"
 	"os"
 
 	"github.com/zitadel/oidc/v3/example/server/exampleop"
 	"github.com/zitadel/oidc/v3/example/server/storage"
-	"golang.org/x/exp/slog"
 )
 
 func main() {
diff --git a/example/server/storage/oidc.go b/example/server/storage/oidc.go
index 63afcf9..2509f77 100644
--- a/example/server/storage/oidc.go
+++ b/example/server/storage/oidc.go
@@ -1,9 +1,9 @@
 package storage
 
 import (
+	"log/slog"
 	"time"
 
-	"golang.org/x/exp/slog"
 	"golang.org/x/text/language"
 
 	"github.com/zitadel/oidc/v3/pkg/oidc"
diff --git a/go.mod b/go.mod
index d1c5f2b..2ae42cb 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/zitadel/oidc/v3
 
-go 1.19
+go 1.21
 
 require (
 	github.com/bmatcuk/doublestar/v4 v4.6.1
@@ -16,11 +16,10 @@ require (
 	github.com/rs/cors v1.10.1
 	github.com/sirupsen/logrus v1.9.3
 	github.com/stretchr/testify v1.8.4
-	github.com/zitadel/logging v0.5.0
+	github.com/zitadel/logging v0.6.0
 	github.com/zitadel/schema v1.3.0
 	go.opentelemetry.io/otel v1.24.0
 	go.opentelemetry.io/otel/trace v1.24.0
-	golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
 	golang.org/x/oauth2 v0.17.0
 	golang.org/x/text v0.14.0
 )
diff --git a/go.sum b/go.sum
index f84f80e..42363b9 100644
--- a/go.sum
+++ b/go.sum
@@ -23,12 +23,14 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo=
 github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
@@ -36,7 +38,9 @@ github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pw
 github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc=
 github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI=
 github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=
 github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=
 github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY=
@@ -53,8 +57,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zitadel/logging v0.5.0 h1:Kunouvqse/efXy4UDvFw5s3vP+Z4AlHo3y8wF7stXHA=
-github.com/zitadel/logging v0.5.0/go.mod h1:IzP5fzwFhzzyxHkSmfF8dsyqFsQRJLLcQmwhIBzlGsE=
+github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank=
+github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow=
 github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0=
 github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc=
 go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
@@ -68,8 +72,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
-golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -136,7 +138,9 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/client/rp/log.go b/pkg/client/rp/log.go
index 6056fa2..556220c 100644
--- a/pkg/client/rp/log.go
+++ b/pkg/client/rp/log.go
@@ -2,9 +2,9 @@ package rp
 
 import (
 	"context"
+	"log/slog"
 
 	"github.com/zitadel/logging"
-	"golang.org/x/exp/slog"
 )
 
 func logCtxWithRPData(ctx context.Context, rp RelyingParty, attrs ...any) context.Context {
diff --git a/pkg/client/rp/relying_party.go b/pkg/client/rp/relying_party.go
index d4bc13c..72270fe 100644
--- a/pkg/client/rp/relying_party.go
+++ b/pkg/client/rp/relying_party.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/base64"
 	"errors"
+	"log/slog"
 	"net/http"
 	"net/url"
 	"time"
@@ -11,7 +12,6 @@ import (
 	"github.com/go-jose/go-jose/v3"
 	"github.com/google/uuid"
 	"github.com/zitadel/logging"
-	"golang.org/x/exp/slog"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/clientcredentials"
 
diff --git a/pkg/oidc/authorization.go b/pkg/oidc/authorization.go
index 511e396..89139ba 100644
--- a/pkg/oidc/authorization.go
+++ b/pkg/oidc/authorization.go
@@ -1,7 +1,7 @@
 package oidc
 
 import (
-	"golang.org/x/exp/slog"
+	"log/slog"
 )
 
 const (
diff --git a/pkg/oidc/error.go b/pkg/oidc/error.go
index b690a23..86f8724 100644
--- a/pkg/oidc/error.go
+++ b/pkg/oidc/error.go
@@ -3,8 +3,7 @@ package oidc
 import (
 	"errors"
 	"fmt"
-
-	"golang.org/x/exp/slog"
+	"log/slog"
 )
 
 type errorType string
diff --git a/pkg/op/auth_request.go b/pkg/op/auth_request.go
index 7058ebc..d570e25 100644
--- a/pkg/op/auth_request.go
+++ b/pkg/op/auth_request.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"log/slog"
 	"net"
 	"net/http"
 	"net/url"
@@ -14,7 +15,6 @@ import (
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
 	str "github.com/zitadel/oidc/v3/pkg/strings"
-	"golang.org/x/exp/slog"
 )
 
 type AuthRequest interface {
diff --git a/pkg/op/error.go b/pkg/op/error.go
index e4580f6..44b1798 100644
--- a/pkg/op/error.go
+++ b/pkg/op/error.go
@@ -4,11 +4,11 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"log/slog"
 	"net/http"
 
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
-	"golang.org/x/exp/slog"
 )
 
 type ErrAuthRequest interface {
diff --git a/pkg/op/mock/authorizer.mock.go b/pkg/op/mock/authorizer.mock.go
index e4297cb..c7703f1 100644
--- a/pkg/op/mock/authorizer.mock.go
+++ b/pkg/op/mock/authorizer.mock.go
@@ -6,12 +6,12 @@ package mock
 
 import (
 	context "context"
+	slog "log/slog"
 	reflect "reflect"
 
 	gomock "github.com/golang/mock/gomock"
 	http "github.com/zitadel/oidc/v3/pkg/http"
 	op "github.com/zitadel/oidc/v3/pkg/op"
-	slog "golang.org/x/exp/slog"
 )
 
 // MockAuthorizer is a mock of Authorizer interface.
diff --git a/pkg/op/op.go b/pkg/op/op.go
index 14c5356..326737a 100644
--- a/pkg/op/op.go
+++ b/pkg/op/op.go
@@ -3,6 +3,7 @@ package op
 import (
 	"context"
 	"fmt"
+	"log/slog"
 	"net/http"
 	"time"
 
@@ -12,7 +13,6 @@ import (
 	"github.com/zitadel/schema"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/trace"
-	"golang.org/x/exp/slog"
 	"golang.org/x/text/language"
 
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
@@ -114,8 +114,6 @@ type OpenIDProvider interface {
 	Crypto() Crypto
 	DefaultLogoutRedirectURI() string
 	Probes() []ProbesFn
-
-	// EXPERIMENTAL: Will change to log/slog import after we drop support for Go 1.20
 	Logger() *slog.Logger
 
 	// Deprecated: Provider now implements http.Handler directly.
@@ -646,8 +644,6 @@ func WithCORSOptions(opts *cors.Options) Option {
 }
 
 // WithLogger lets a logger other than slog.Default().
-//
-// EXPERIMENTAL: Will change to log/slog import after we drop support for Go 1.20
 func WithLogger(logger *slog.Logger) Option {
 	return func(o *Provider) error {
 		o.logger = logger
diff --git a/pkg/op/server_http.go b/pkg/op/server_http.go
index 2220e44..0a5e469 100644
--- a/pkg/op/server_http.go
+++ b/pkg/op/server_http.go
@@ -2,6 +2,7 @@ package op
 
 import (
 	"context"
+	"log/slog"
 	"net/http"
 	"net/url"
 
@@ -11,7 +12,6 @@ import (
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
 	"github.com/zitadel/schema"
-	"golang.org/x/exp/slog"
 )
 
 // RegisterServer registers an implementation of Server.
diff --git a/pkg/op/session.go b/pkg/op/session.go
index c933659..6af7d7c 100644
--- a/pkg/op/session.go
+++ b/pkg/op/session.go
@@ -3,13 +3,13 @@ package op
 import (
 	"context"
 	"errors"
+	"log/slog"
 	"net/http"
 	"net/url"
 	"path"
 
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
-	"golang.org/x/exp/slog"
 )
 
 type SessionEnder interface {
diff --git a/pkg/op/token_request.go b/pkg/op/token_request.go
index f00b294..2006725 100644
--- a/pkg/op/token_request.go
+++ b/pkg/op/token_request.go
@@ -2,12 +2,12 @@ package op
 
 import (
 	"context"
+	"log/slog"
 	"net/http"
 	"net/url"
 
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
-	"golang.org/x/exp/slog"
 )
 
 type Exchanger interface {


Test patch:
diff --git a/pkg/client/integration_test.go b/pkg/client/integration_test.go
index ce77f5e..9145c1e 100644
--- a/pkg/client/integration_test.go
+++ b/pkg/client/integration_test.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"log/slog"
 	"math/rand"
 	"net/http"
 	"net/http/cookiejar"
@@ -20,7 +21,6 @@ import (
 	"github.com/jeremija/gosubmit"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"golang.org/x/exp/slog"
 	"golang.org/x/oauth2"
 
 	"github.com/zitadel/oidc/v3/example/server/exampleop"
diff --git a/pkg/oidc/authorization_test.go b/pkg/oidc/authorization_test.go
index 573d65c..1446efa 100644
--- a/pkg/oidc/authorization_test.go
+++ b/pkg/oidc/authorization_test.go
@@ -3,10 +3,10 @@
 package oidc
 
 import (
+	"log/slog"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"golang.org/x/exp/slog"
 )
 
 func TestAuthRequest_LogValue(t *testing.T) {
diff --git a/pkg/oidc/error_go120_test.go b/pkg/oidc/error_go120_test.go
deleted file mode 100644
index 399d7f7..0000000
--- a/pkg/oidc/error_go120_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-//go:build go1.20
-
-package oidc
-
-import (
-	"io"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"golang.org/x/exp/slog"
-)
-
-func TestError_LogValue(t *testing.T) {
-	type fields struct {
-		Parent           error
-		ErrorType        errorType
-		Description      string
-		State            string
-		redirectDisabled bool
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   slog.Value
-	}{
-		{
-			name: "parent",
-			fields: fields{
-				Parent: io.EOF,
-			},
-			want: slog.GroupValue(slog.Any("parent", io.EOF)),
-		},
-		{
-			name: "description",
-			fields: fields{
-				Description: "oops",
-			},
-			want: slog.GroupValue(slog.String("description", "oops")),
-		},
-		{
-			name: "errorType",
-			fields: fields{
-				ErrorType: ExpiredToken,
-			},
-			want: slog.GroupValue(slog.String("type", string(ExpiredToken))),
-		},
-		{
-			name: "state",
-			fields: fields{
-				State: "123",
-			},
-			want: slog.GroupValue(slog.String("state", "123")),
-		},
-		{
-			name: "all fields",
-			fields: fields{
-				Parent:      io.EOF,
-				Description: "oops",
-				ErrorType:   ExpiredToken,
-				State:       "123",
-			},
-			want: slog.GroupValue(
-				slog.Any("parent", io.EOF),
-				slog.String("description", "oops"),
-				slog.String("type", string(ExpiredToken)),
-				slog.String("state", "123"),
-			),
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &Error{
-				Parent:           tt.fields.Parent,
-				ErrorType:        tt.fields.ErrorType,
-				Description:      tt.fields.Description,
-				State:            tt.fields.State,
-				redirectDisabled: tt.fields.redirectDisabled,
-			}
-			got := e.LogValue()
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}
diff --git a/pkg/oidc/error_test.go b/pkg/oidc/error_test.go
index 0554c8f..2eeb4e6 100644
--- a/pkg/oidc/error_test.go
+++ b/pkg/oidc/error_test.go
@@ -2,10 +2,10 @@ package oidc
 
 import (
 	"io"
+	"log/slog"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"golang.org/x/exp/slog"
 )
 
 func TestDefaultToServerError(t *testing.T) {
@@ -79,3 +79,75 @@ func TestError_LogLevel(t *testing.T) {
 		})
 	}
 }
+
+func TestError_LogValue(t *testing.T) {
+	type fields struct {
+		Parent           error
+		ErrorType        errorType
+		Description      string
+		State            string
+		redirectDisabled bool
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   slog.Value
+	}{
+		{
+			name: "parent",
+			fields: fields{
+				Parent: io.EOF,
+			},
+			want: slog.GroupValue(slog.Any("parent", io.EOF)),
+		},
+		{
+			name: "description",
+			fields: fields{
+				Description: "oops",
+			},
+			want: slog.GroupValue(slog.String("description", "oops")),
+		},
+		{
+			name: "errorType",
+			fields: fields{
+				ErrorType: ExpiredToken,
+			},
+			want: slog.GroupValue(slog.String("type", string(ExpiredToken))),
+		},
+		{
+			name: "state",
+			fields: fields{
+				State: "123",
+			},
+			want: slog.GroupValue(slog.String("state", "123")),
+		},
+		{
+			name: "all fields",
+			fields: fields{
+				Parent:      io.EOF,
+				Description: "oops",
+				ErrorType:   ExpiredToken,
+				State:       "123",
+			},
+			want: slog.GroupValue(
+				slog.Any("parent", io.EOF),
+				slog.String("description", "oops"),
+				slog.String("type", string(ExpiredToken)),
+				slog.String("state", "123"),
+			),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := &Error{
+				Parent:           tt.fields.Parent,
+				ErrorType:        tt.fields.ErrorType,
+				Description:      tt.fields.Description,
+				State:            tt.fields.State,
+				redirectDisabled: tt.fields.redirectDisabled,
+			}
+			got := e.LogValue()
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
diff --git a/pkg/op/auth_request_test.go b/pkg/op/auth_request_test.go
index 18880f0..2e7c75c 100644
--- a/pkg/op/auth_request_test.go
+++ b/pkg/op/auth_request_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"io"
+	"log/slog"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -20,7 +21,6 @@ import (
 	"github.com/zitadel/oidc/v3/pkg/op"
 	"github.com/zitadel/oidc/v3/pkg/op/mock"
 	"github.com/zitadel/schema"
-	"golang.org/x/exp/slog"
 )
 
 func TestAuthorize(t *testing.T) {
diff --git a/pkg/op/error_test.go b/pkg/op/error_test.go
index 50a9cbf..170039c 100644
--- a/pkg/op/error_test.go
+++ b/pkg/op/error_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"log/slog"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -14,7 +15,6 @@ import (
 	"github.com/stretchr/testify/require"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
 	"github.com/zitadel/schema"
-	"golang.org/x/exp/slog"
 )
 
 func TestAuthRequestError(t *testing.T) {
diff --git a/pkg/op/server_http_test.go b/pkg/op/server_http_test.go
index 6cb268f..9ff07bc 100644
--- a/pkg/op/server_http_test.go
+++ b/pkg/op/server_http_test.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"log/slog"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -19,7 +20,6 @@ import (
 	httphelper "github.com/zitadel/oidc/v3/pkg/http"
 	"github.com/zitadel/oidc/v3/pkg/oidc"
 	"github.com/zitadel/schema"
-	"golang.org/x/exp/slog"
 )
 
 func TestRegisterServer(t *testing.T) {