Repository: zitadel/oidc
Pull request #270 (2023-01-30 14:28:20)

feat(op): add support for client credentials


Patch:
diff --git a/pkg/oidc/grants/client_credentials.go b/pkg/oidc/grants/client_credentials.go
index 998dda1..e9f467e 100644
--- a/pkg/oidc/grants/client_credentials.go
+++ b/pkg/oidc/grants/client_credentials.go
@@ -14,7 +14,7 @@ type clientCredentialsGrant struct {
 }
 
 //ClientCredentialsGrantBasic creates an oauth2 `Client Credentials` Grant
-//sneding client_id and client_secret as basic auth header
+//sending client_id and client_secret as basic auth header
 func ClientCredentialsGrantBasic(scopes ...string) *clientCredentialsGrantBasic {
 	return &clientCredentialsGrantBasic{
 		grantType: "client_credentials",
@@ -23,7 +23,7 @@ func ClientCredentialsGrantBasic(scopes ...string) *clientCredentialsGrantBasic
 }
 
 //ClientCredentialsGrantValues creates an oauth2 `Client Credentials` Grant
-//sneding client_id and client_secret as form values
+//sending client_id and client_secret as form values
 func ClientCredentialsGrantValues(clientID, clientSecret string, scopes ...string) *clientCredentialsGrant {
 	return &clientCredentialsGrant{
 		clientCredentialsGrantBasic: ClientCredentialsGrantBasic(scopes...),
diff --git a/pkg/oidc/token_request.go b/pkg/oidc/token_request.go
index f260f32..79523ef 100644
--- a/pkg/oidc/token_request.go
+++ b/pkg/oidc/token_request.go
@@ -15,6 +15,9 @@ const (
 	//GrantTypeRefreshToken defines the grant_type `refresh_token` used for the Token Request in the Refresh Token Flow
 	GrantTypeRefreshToken GrantType = "refresh_token"
 
+	//GrantTypeClientCredentials defines the grant_type `client_credentials` used for the Token Request in the Client Credentials Token Flow
+	GrantTypeClientCredentials GrantType = "client_credentials"
+
 	//GrantTypeBearer defines the grant_type `urn:ietf:params:oauth:grant-type:jwt-bearer` used for the JWT Authorization Grant
 	GrantTypeBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
 
@@ -198,3 +201,12 @@ type TokenExchangeRequest struct {
 	Scope              SpaceDelimitedArray `schema:"scope"`
 	requestedTokenType string              `schema:"requested_token_type"`
 }
+
+type ClientCredentialsRequest struct {
+	GrantType           GrantType           `schema:"grant_type"`
+	Scope               SpaceDelimitedArray `schema:"scope"`
+	ClientID            string              `schema:"client_id"`
+	ClientSecret        string              `schema:"client_secret"`
+	ClientAssertion     string              `schema:"client_assertion"`
+	ClientAssertionType string              `schema:"client_assertion_type"`
+}
diff --git a/pkg/op/config.go b/pkg/op/config.go
index 7b097c4..c40fa2d 100644
--- a/pkg/op/config.go
+++ b/pkg/op/config.go
@@ -35,6 +35,7 @@ type Configuration interface {
 	GrantTypeRefreshTokenSupported() bool
 	GrantTypeTokenExchangeSupported() bool
 	GrantTypeJWTAuthorizationSupported() bool
+	GrantTypeClientCredentialsSupported() bool
 	IntrospectionAuthMethodPrivateKeyJWTSupported() bool
 	IntrospectionEndpointSigningAlgorithmsSupported() []string
 	RevocationAuthMethodPrivateKeyJWTSupported() bool
diff --git a/pkg/op/discovery.go b/pkg/op/discovery.go
index ce3240b..dd8bd91 100644
--- a/pkg/op/discovery.go
+++ b/pkg/op/discovery.go
@@ -83,6 +83,9 @@ func GrantTypes(c Configuration) []oidc.GrantType {
 	if c.GrantTypeRefreshTokenSupported() {
 		grantTypes = append(grantTypes, oidc.GrantTypeRefreshToken)
 	}
+	if c.GrantTypeClientCredentialsSupported() {
+		grantTypes = append(grantTypes, oidc.GrantTypeClientCredentials)
+	}
 	if c.GrantTypeTokenExchangeSupported() {
 		grantTypes = append(grantTypes, oidc.GrantTypeTokenExchange)
 	}
diff --git a/pkg/op/mock/authorizer.mock.go b/pkg/op/mock/authorizer.mock.go
index 179f4c4..2efbe53 100644
--- a/pkg/op/mock/authorizer.mock.go
+++ b/pkg/op/mock/authorizer.mock.go
@@ -1,43 +1,41 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: Authorizer)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: Authorizer)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
 	context "context"
-	reflect "reflect"
-
 	gomock "github.com/golang/mock/gomock"
-
 	http "github.com/zitadel/oidc/v2/pkg/http"
 	op "github.com/zitadel/oidc/v2/pkg/op"
+	reflect "reflect"
 )
 
-// MockAuthorizer is a mock of Authorizer interface.
+// MockAuthorizer is a mock of Authorizer interface
 type MockAuthorizer struct {
 	ctrl     *gomock.Controller
 	recorder *MockAuthorizerMockRecorder
 }
 
-// MockAuthorizerMockRecorder is the mock recorder for MockAuthorizer.
+// MockAuthorizerMockRecorder is the mock recorder for MockAuthorizer
 type MockAuthorizerMockRecorder struct {
 	mock *MockAuthorizer
 }
 
-// NewMockAuthorizer creates a new mock instance.
+// NewMockAuthorizer creates a new mock instance
 func NewMockAuthorizer(ctrl *gomock.Controller) *MockAuthorizer {
 	mock := &MockAuthorizer{ctrl: ctrl}
 	mock.recorder = &MockAuthorizerMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockAuthorizer) EXPECT() *MockAuthorizerMockRecorder {
 	return m.recorder
 }
 
-// Crypto mocks base method.
+// Crypto mocks base method
 func (m *MockAuthorizer) Crypto() op.Crypto {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Crypto")
@@ -45,13 +43,13 @@ func (m *MockAuthorizer) Crypto() op.Crypto {
 	return ret0
 }
 
-// Crypto indicates an expected call of Crypto.
+// Crypto indicates an expected call of Crypto
 func (mr *MockAuthorizerMockRecorder) Crypto() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Crypto", reflect.TypeOf((*MockAuthorizer)(nil).Crypto))
 }
 
-// Decoder mocks base method.
+// Decoder mocks base method
 func (m *MockAuthorizer) Decoder() http.Decoder {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Decoder")
@@ -59,13 +57,13 @@ func (m *MockAuthorizer) Decoder() http.Decoder {
 	return ret0
 }
 
-// Decoder indicates an expected call of Decoder.
+// Decoder indicates an expected call of Decoder
 func (mr *MockAuthorizerMockRecorder) Decoder() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decoder", reflect.TypeOf((*MockAuthorizer)(nil).Decoder))
 }
 
-// Encoder mocks base method.
+// Encoder mocks base method
 func (m *MockAuthorizer) Encoder() http.Encoder {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Encoder")
@@ -73,13 +71,13 @@ func (m *MockAuthorizer) Encoder() http.Encoder {
 	return ret0
 }
 
-// Encoder indicates an expected call of Encoder.
+// Encoder indicates an expected call of Encoder
 func (mr *MockAuthorizerMockRecorder) Encoder() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Encoder", reflect.TypeOf((*MockAuthorizer)(nil).Encoder))
 }
 
-// IDTokenHintVerifier mocks base method.
+// IDTokenHintVerifier mocks base method
 func (m *MockAuthorizer) IDTokenHintVerifier(arg0 context.Context) op.IDTokenHintVerifier {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IDTokenHintVerifier", arg0)
@@ -87,13 +85,13 @@ func (m *MockAuthorizer) IDTokenHintVerifier(arg0 context.Context) op.IDTokenHin
 	return ret0
 }
 
-// IDTokenHintVerifier indicates an expected call of IDTokenHintVerifier.
+// IDTokenHintVerifier indicates an expected call of IDTokenHintVerifier
 func (mr *MockAuthorizerMockRecorder) IDTokenHintVerifier(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDTokenHintVerifier", reflect.TypeOf((*MockAuthorizer)(nil).IDTokenHintVerifier), arg0)
 }
 
-// RequestObjectSupported mocks base method.
+// RequestObjectSupported mocks base method
 func (m *MockAuthorizer) RequestObjectSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RequestObjectSupported")
@@ -101,13 +99,13 @@ func (m *MockAuthorizer) RequestObjectSupported() bool {
 	return ret0
 }
 
-// RequestObjectSupported indicates an expected call of RequestObjectSupported.
+// RequestObjectSupported indicates an expected call of RequestObjectSupported
 func (mr *MockAuthorizerMockRecorder) RequestObjectSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestObjectSupported", reflect.TypeOf((*MockAuthorizer)(nil).RequestObjectSupported))
 }
 
-// Storage mocks base method.
+// Storage mocks base method
 func (m *MockAuthorizer) Storage() op.Storage {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Storage")
@@ -115,7 +113,7 @@ func (m *MockAuthorizer) Storage() op.Storage {
 	return ret0
 }
 
-// Storage indicates an expected call of Storage.
+// Storage indicates an expected call of Storage
 func (mr *MockAuthorizerMockRecorder) Storage() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storage", reflect.TypeOf((*MockAuthorizer)(nil).Storage))
diff --git a/pkg/op/mock/client.mock.go b/pkg/op/mock/client.mock.go
index 028a56f..af4ea52 100644
--- a/pkg/op/mock/client.mock.go
+++ b/pkg/op/mock/client.mock.go
@@ -1,43 +1,41 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: Client)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: Client)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
-	reflect "reflect"
-	time "time"
-
 	gomock "github.com/golang/mock/gomock"
-
 	oidc "github.com/zitadel/oidc/v2/pkg/oidc"
 	op "github.com/zitadel/oidc/v2/pkg/op"
+	reflect "reflect"
+	time "time"
 )
 
-// MockClient is a mock of Client interface.
+// MockClient is a mock of Client interface
 type MockClient struct {
 	ctrl     *gomock.Controller
 	recorder *MockClientMockRecorder
 }
 
-// MockClientMockRecorder is the mock recorder for MockClient.
+// MockClientMockRecorder is the mock recorder for MockClient
 type MockClientMockRecorder struct {
 	mock *MockClient
 }
 
-// NewMockClient creates a new mock instance.
+// NewMockClient creates a new mock instance
 func NewMockClient(ctrl *gomock.Controller) *MockClient {
 	mock := &MockClient{ctrl: ctrl}
 	mock.recorder = &MockClientMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockClient) EXPECT() *MockClientMockRecorder {
 	return m.recorder
 }
 
-// AccessTokenType mocks base method.
+// AccessTokenType mocks base method
 func (m *MockClient) AccessTokenType() op.AccessTokenType {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AccessTokenType")
@@ -45,13 +43,13 @@ func (m *MockClient) AccessTokenType() op.AccessTokenType {
 	return ret0
 }
 
-// AccessTokenType indicates an expected call of AccessTokenType.
+// AccessTokenType indicates an expected call of AccessTokenType
 func (mr *MockClientMockRecorder) AccessTokenType() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenType", reflect.TypeOf((*MockClient)(nil).AccessTokenType))
 }
 
-// ApplicationType mocks base method.
+// ApplicationType mocks base method
 func (m *MockClient) ApplicationType() op.ApplicationType {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ApplicationType")
@@ -59,13 +57,13 @@ func (m *MockClient) ApplicationType() op.ApplicationType {
 	return ret0
 }
 
-// ApplicationType indicates an expected call of ApplicationType.
+// ApplicationType indicates an expected call of ApplicationType
 func (mr *MockClientMockRecorder) ApplicationType() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplicationType", reflect.TypeOf((*MockClient)(nil).ApplicationType))
 }
 
-// AuthMethod mocks base method.
+// AuthMethod mocks base method
 func (m *MockClient) AuthMethod() oidc.AuthMethod {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthMethod")
@@ -73,13 +71,13 @@ func (m *MockClient) AuthMethod() oidc.AuthMethod {
 	return ret0
 }
 
-// AuthMethod indicates an expected call of AuthMethod.
+// AuthMethod indicates an expected call of AuthMethod
 func (mr *MockClientMockRecorder) AuthMethod() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethod", reflect.TypeOf((*MockClient)(nil).AuthMethod))
 }
 
-// ClockSkew mocks base method.
+// ClockSkew mocks base method
 func (m *MockClient) ClockSkew() time.Duration {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ClockSkew")
@@ -87,13 +85,13 @@ func (m *MockClient) ClockSkew() time.Duration {
 	return ret0
 }
 
-// ClockSkew indicates an expected call of ClockSkew.
+// ClockSkew indicates an expected call of ClockSkew
 func (mr *MockClientMockRecorder) ClockSkew() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClockSkew", reflect.TypeOf((*MockClient)(nil).ClockSkew))
 }
 
-// DevMode mocks base method.
+// DevMode mocks base method
 func (m *MockClient) DevMode() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "DevMode")
@@ -101,13 +99,13 @@ func (m *MockClient) DevMode() bool {
 	return ret0
 }
 
-// DevMode indicates an expected call of DevMode.
+// DevMode indicates an expected call of DevMode
 func (mr *MockClientMockRecorder) DevMode() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DevMode", reflect.TypeOf((*MockClient)(nil).DevMode))
 }
 
-// GetID mocks base method.
+// GetID mocks base method
 func (m *MockClient) GetID() string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetID")
@@ -115,13 +113,13 @@ func (m *MockClient) GetID() string {
 	return ret0
 }
 
-// GetID indicates an expected call of GetID.
+// GetID indicates an expected call of GetID
 func (mr *MockClientMockRecorder) GetID() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetID", reflect.TypeOf((*MockClient)(nil).GetID))
 }
 
-// GrantTypes mocks base method.
+// GrantTypes mocks base method
 func (m *MockClient) GrantTypes() []oidc.GrantType {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GrantTypes")
@@ -129,13 +127,13 @@ func (m *MockClient) GrantTypes() []oidc.GrantType {
 	return ret0
 }
 
-// GrantTypes indicates an expected call of GrantTypes.
+// GrantTypes indicates an expected call of GrantTypes
 func (mr *MockClientMockRecorder) GrantTypes() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypes", reflect.TypeOf((*MockClient)(nil).GrantTypes))
 }
 
-// IDTokenLifetime mocks base method.
+// IDTokenLifetime mocks base method
 func (m *MockClient) IDTokenLifetime() time.Duration {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IDTokenLifetime")
@@ -143,13 +141,13 @@ func (m *MockClient) IDTokenLifetime() time.Duration {
 	return ret0
 }
 
-// IDTokenLifetime indicates an expected call of IDTokenLifetime.
+// IDTokenLifetime indicates an expected call of IDTokenLifetime
 func (mr *MockClientMockRecorder) IDTokenLifetime() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDTokenLifetime", reflect.TypeOf((*MockClient)(nil).IDTokenLifetime))
 }
 
-// IDTokenUserinfoClaimsAssertion mocks base method.
+// IDTokenUserinfoClaimsAssertion mocks base method
 func (m *MockClient) IDTokenUserinfoClaimsAssertion() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IDTokenUserinfoClaimsAssertion")
@@ -157,13 +155,13 @@ func (m *MockClient) IDTokenUserinfoClaimsAssertion() bool {
 	return ret0
 }
 
-// IDTokenUserinfoClaimsAssertion indicates an expected call of IDTokenUserinfoClaimsAssertion.
+// IDTokenUserinfoClaimsAssertion indicates an expected call of IDTokenUserinfoClaimsAssertion
 func (mr *MockClientMockRecorder) IDTokenUserinfoClaimsAssertion() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDTokenUserinfoClaimsAssertion", reflect.TypeOf((*MockClient)(nil).IDTokenUserinfoClaimsAssertion))
 }
 
-// IsScopeAllowed mocks base method.
+// IsScopeAllowed mocks base method
 func (m *MockClient) IsScopeAllowed(arg0 string) bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IsScopeAllowed", arg0)
@@ -171,13 +169,13 @@ func (m *MockClient) IsScopeAllowed(arg0 string) bool {
 	return ret0
 }
 
-// IsScopeAllowed indicates an expected call of IsScopeAllowed.
+// IsScopeAllowed indicates an expected call of IsScopeAllowed
 func (mr *MockClientMockRecorder) IsScopeAllowed(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsScopeAllowed", reflect.TypeOf((*MockClient)(nil).IsScopeAllowed), arg0)
 }
 
-// LoginURL mocks base method.
+// LoginURL mocks base method
 func (m *MockClient) LoginURL(arg0 string) string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "LoginURL", arg0)
@@ -185,13 +183,13 @@ func (m *MockClient) LoginURL(arg0 string) string {
 	return ret0
 }
 
-// LoginURL indicates an expected call of LoginURL.
+// LoginURL indicates an expected call of LoginURL
 func (mr *MockClientMockRecorder) LoginURL(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoginURL", reflect.TypeOf((*MockClient)(nil).LoginURL), arg0)
 }
 
-// PostLogoutRedirectURIs mocks base method.
+// PostLogoutRedirectURIs mocks base method
 func (m *MockClient) PostLogoutRedirectURIs() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "PostLogoutRedirectURIs")
@@ -199,13 +197,13 @@ func (m *MockClient) PostLogoutRedirectURIs() []string {
 	return ret0
 }
 
-// PostLogoutRedirectURIs indicates an expected call of PostLogoutRedirectURIs.
+// PostLogoutRedirectURIs indicates an expected call of PostLogoutRedirectURIs
 func (mr *MockClientMockRecorder) PostLogoutRedirectURIs() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostLogoutRedirectURIs", reflect.TypeOf((*MockClient)(nil).PostLogoutRedirectURIs))
 }
 
-// RedirectURIs mocks base method.
+// RedirectURIs mocks base method
 func (m *MockClient) RedirectURIs() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RedirectURIs")
@@ -213,13 +211,13 @@ func (m *MockClient) RedirectURIs() []string {
 	return ret0
 }
 
-// RedirectURIs indicates an expected call of RedirectURIs.
+// RedirectURIs indicates an expected call of RedirectURIs
 func (mr *MockClientMockRecorder) RedirectURIs() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RedirectURIs", reflect.TypeOf((*MockClient)(nil).RedirectURIs))
 }
 
-// ResponseTypes mocks base method.
+// ResponseTypes mocks base method
 func (m *MockClient) ResponseTypes() []oidc.ResponseType {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ResponseTypes")
@@ -227,13 +225,13 @@ func (m *MockClient) ResponseTypes() []oidc.ResponseType {
 	return ret0
 }
 
-// ResponseTypes indicates an expected call of ResponseTypes.
+// ResponseTypes indicates an expected call of ResponseTypes
 func (mr *MockClientMockRecorder) ResponseTypes() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResponseTypes", reflect.TypeOf((*MockClient)(nil).ResponseTypes))
 }
 
-// RestrictAdditionalAccessTokenScopes mocks base method.
+// RestrictAdditionalAccessTokenScopes mocks base method
 func (m *MockClient) RestrictAdditionalAccessTokenScopes() func([]string) []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RestrictAdditionalAccessTokenScopes")
@@ -241,13 +239,13 @@ func (m *MockClient) RestrictAdditionalAccessTokenScopes() func([]string) []stri
 	return ret0
 }
 
-// RestrictAdditionalAccessTokenScopes indicates an expected call of RestrictAdditionalAccessTokenScopes.
+// RestrictAdditionalAccessTokenScopes indicates an expected call of RestrictAdditionalAccessTokenScopes
 func (mr *MockClientMockRecorder) RestrictAdditionalAccessTokenScopes() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestrictAdditionalAccessTokenScopes", reflect.TypeOf((*MockClient)(nil).RestrictAdditionalAccessTokenScopes))
 }
 
-// RestrictAdditionalIdTokenScopes mocks base method.
+// RestrictAdditionalIdTokenScopes mocks base method
 func (m *MockClient) RestrictAdditionalIdTokenScopes() func([]string) []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RestrictAdditionalIdTokenScopes")
@@ -255,7 +253,7 @@ func (m *MockClient) RestrictAdditionalIdTokenScopes() func([]string) []string {
 	return ret0
 }
 
-// RestrictAdditionalIdTokenScopes indicates an expected call of RestrictAdditionalIdTokenScopes.
+// RestrictAdditionalIdTokenScopes indicates an expected call of RestrictAdditionalIdTokenScopes
 func (mr *MockClientMockRecorder) RestrictAdditionalIdTokenScopes() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestrictAdditionalIdTokenScopes", reflect.TypeOf((*MockClient)(nil).RestrictAdditionalIdTokenScopes))
diff --git a/pkg/op/mock/configuration.mock.go b/pkg/op/mock/configuration.mock.go
index df371ce..85e6f8c 100644
--- a/pkg/op/mock/configuration.mock.go
+++ b/pkg/op/mock/configuration.mock.go
@@ -1,43 +1,41 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: Configuration)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: Configuration)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
-	http "net/http"
-	reflect "reflect"
-
 	gomock "github.com/golang/mock/gomock"
-	language "golang.org/x/text/language"
-
 	op "github.com/zitadel/oidc/v2/pkg/op"
+	language "golang.org/x/text/language"
+	http "net/http"
+	reflect "reflect"
 )
 
-// MockConfiguration is a mock of Configuration interface.
+// MockConfiguration is a mock of Configuration interface
 type MockConfiguration struct {
 	ctrl     *gomock.Controller
 	recorder *MockConfigurationMockRecorder
 }
 
-// MockConfigurationMockRecorder is the mock recorder for MockConfiguration.
+// MockConfigurationMockRecorder is the mock recorder for MockConfiguration
 type MockConfigurationMockRecorder struct {
 	mock *MockConfiguration
 }
 
-// NewMockConfiguration creates a new mock instance.
+// NewMockConfiguration creates a new mock instance
 func NewMockConfiguration(ctrl *gomock.Controller) *MockConfiguration {
 	mock := &MockConfiguration{ctrl: ctrl}
 	mock.recorder = &MockConfigurationMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockConfiguration) EXPECT() *MockConfigurationMockRecorder {
 	return m.recorder
 }
 
-// AuthMethodPostSupported mocks base method.
+// AuthMethodPostSupported mocks base method
 func (m *MockConfiguration) AuthMethodPostSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthMethodPostSupported")
@@ -45,13 +43,13 @@ func (m *MockConfiguration) AuthMethodPostSupported() bool {
 	return ret0
 }
 
-// AuthMethodPostSupported indicates an expected call of AuthMethodPostSupported.
+// AuthMethodPostSupported indicates an expected call of AuthMethodPostSupported
 func (mr *MockConfigurationMockRecorder) AuthMethodPostSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPostSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPostSupported))
 }
 
-// AuthMethodPrivateKeyJWTSupported mocks base method.
+// AuthMethodPrivateKeyJWTSupported mocks base method
 func (m *MockConfiguration) AuthMethodPrivateKeyJWTSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthMethodPrivateKeyJWTSupported")
@@ -59,13 +57,13 @@ func (m *MockConfiguration) AuthMethodPrivateKeyJWTSupported() bool {
 	return ret0
 }
 
-// AuthMethodPrivateKeyJWTSupported indicates an expected call of AuthMethodPrivateKeyJWTSupported.
+// AuthMethodPrivateKeyJWTSupported indicates an expected call of AuthMethodPrivateKeyJWTSupported
 func (mr *MockConfigurationMockRecorder) AuthMethodPrivateKeyJWTSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthMethodPrivateKeyJWTSupported", reflect.TypeOf((*MockConfiguration)(nil).AuthMethodPrivateKeyJWTSupported))
 }
 
-// AuthorizationEndpoint mocks base method.
+// AuthorizationEndpoint mocks base method
 func (m *MockConfiguration) AuthorizationEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthorizationEndpoint")
@@ -73,13 +71,13 @@ func (m *MockConfiguration) AuthorizationEndpoint() op.Endpoint {
 	return ret0
 }
 
-// AuthorizationEndpoint indicates an expected call of AuthorizationEndpoint.
+// AuthorizationEndpoint indicates an expected call of AuthorizationEndpoint
 func (mr *MockConfigurationMockRecorder) AuthorizationEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizationEndpoint", reflect.TypeOf((*MockConfiguration)(nil).AuthorizationEndpoint))
 }
 
-// CodeMethodS256Supported mocks base method.
+// CodeMethodS256Supported mocks base method
 func (m *MockConfiguration) CodeMethodS256Supported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "CodeMethodS256Supported")
@@ -87,13 +85,13 @@ func (m *MockConfiguration) CodeMethodS256Supported() bool {
 	return ret0
 }
 
-// CodeMethodS256Supported indicates an expected call of CodeMethodS256Supported.
+// CodeMethodS256Supported indicates an expected call of CodeMethodS256Supported
 func (mr *MockConfigurationMockRecorder) CodeMethodS256Supported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeMethodS256Supported", reflect.TypeOf((*MockConfiguration)(nil).CodeMethodS256Supported))
 }
 
-// EndSessionEndpoint mocks base method.
+// EndSessionEndpoint mocks base method
 func (m *MockConfiguration) EndSessionEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "EndSessionEndpoint")
@@ -101,13 +99,27 @@ func (m *MockConfiguration) EndSessionEndpoint() op.Endpoint {
 	return ret0
 }
 
-// EndSessionEndpoint indicates an expected call of EndSessionEndpoint.
+// EndSessionEndpoint indicates an expected call of EndSessionEndpoint
 func (mr *MockConfigurationMockRecorder) EndSessionEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndSessionEndpoint", reflect.TypeOf((*MockConfiguration)(nil).EndSessionEndpoint))
 }
 
-// GrantTypeJWTAuthorizationSupported mocks base method.
+// GrantTypeClientCredentialsSupported mocks base method
+func (m *MockConfiguration) GrantTypeClientCredentialsSupported() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GrantTypeClientCredentialsSupported")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// GrantTypeClientCredentialsSupported indicates an expected call of GrantTypeClientCredentialsSupported
+func (mr *MockConfigurationMockRecorder) GrantTypeClientCredentialsSupported() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeClientCredentialsSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeClientCredentialsSupported))
+}
+
+// GrantTypeJWTAuthorizationSupported mocks base method
 func (m *MockConfiguration) GrantTypeJWTAuthorizationSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GrantTypeJWTAuthorizationSupported")
@@ -115,13 +127,13 @@ func (m *MockConfiguration) GrantTypeJWTAuthorizationSupported() bool {
 	return ret0
 }
 
-// GrantTypeJWTAuthorizationSupported indicates an expected call of GrantTypeJWTAuthorizationSupported.
+// GrantTypeJWTAuthorizationSupported indicates an expected call of GrantTypeJWTAuthorizationSupported
 func (mr *MockConfigurationMockRecorder) GrantTypeJWTAuthorizationSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeJWTAuthorizationSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeJWTAuthorizationSupported))
 }
 
-// GrantTypeRefreshTokenSupported mocks base method.
+// GrantTypeRefreshTokenSupported mocks base method
 func (m *MockConfiguration) GrantTypeRefreshTokenSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GrantTypeRefreshTokenSupported")
@@ -129,13 +141,13 @@ func (m *MockConfiguration) GrantTypeRefreshTokenSupported() bool {
 	return ret0
 }
 
-// GrantTypeRefreshTokenSupported indicates an expected call of GrantTypeRefreshTokenSupported.
+// GrantTypeRefreshTokenSupported indicates an expected call of GrantTypeRefreshTokenSupported
 func (mr *MockConfigurationMockRecorder) GrantTypeRefreshTokenSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeRefreshTokenSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeRefreshTokenSupported))
 }
 
-// GrantTypeTokenExchangeSupported mocks base method.
+// GrantTypeTokenExchangeSupported mocks base method
 func (m *MockConfiguration) GrantTypeTokenExchangeSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GrantTypeTokenExchangeSupported")
@@ -143,13 +155,13 @@ func (m *MockConfiguration) GrantTypeTokenExchangeSupported() bool {
 	return ret0
 }
 
-// GrantTypeTokenExchangeSupported indicates an expected call of GrantTypeTokenExchangeSupported.
+// GrantTypeTokenExchangeSupported indicates an expected call of GrantTypeTokenExchangeSupported
 func (mr *MockConfigurationMockRecorder) GrantTypeTokenExchangeSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantTypeTokenExchangeSupported", reflect.TypeOf((*MockConfiguration)(nil).GrantTypeTokenExchangeSupported))
 }
 
-// Insecure mocks base method.
+// Insecure mocks base method
 func (m *MockConfiguration) Insecure() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Insecure")
@@ -157,13 +169,13 @@ func (m *MockConfiguration) Insecure() bool {
 	return ret0
 }
 
-// Insecure indicates an expected call of Insecure.
+// Insecure indicates an expected call of Insecure
 func (mr *MockConfigurationMockRecorder) Insecure() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insecure", reflect.TypeOf((*MockConfiguration)(nil).Insecure))
 }
 
-// IntrospectionAuthMethodPrivateKeyJWTSupported mocks base method.
+// IntrospectionAuthMethodPrivateKeyJWTSupported mocks base method
 func (m *MockConfiguration) IntrospectionAuthMethodPrivateKeyJWTSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IntrospectionAuthMethodPrivateKeyJWTSupported")
@@ -171,13 +183,13 @@ func (m *MockConfiguration) IntrospectionAuthMethodPrivateKeyJWTSupported() bool
 	return ret0
 }
 
-// IntrospectionAuthMethodPrivateKeyJWTSupported indicates an expected call of IntrospectionAuthMethodPrivateKeyJWTSupported.
+// IntrospectionAuthMethodPrivateKeyJWTSupported indicates an expected call of IntrospectionAuthMethodPrivateKeyJWTSupported
 func (mr *MockConfigurationMockRecorder) IntrospectionAuthMethodPrivateKeyJWTSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectionAuthMethodPrivateKeyJWTSupported", reflect.TypeOf((*MockConfiguration)(nil).IntrospectionAuthMethodPrivateKeyJWTSupported))
 }
 
-// IntrospectionEndpoint mocks base method.
+// IntrospectionEndpoint mocks base method
 func (m *MockConfiguration) IntrospectionEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IntrospectionEndpoint")
@@ -185,13 +197,13 @@ func (m *MockConfiguration) IntrospectionEndpoint() op.Endpoint {
 	return ret0
 }
 
-// IntrospectionEndpoint indicates an expected call of IntrospectionEndpoint.
+// IntrospectionEndpoint indicates an expected call of IntrospectionEndpoint
 func (mr *MockConfigurationMockRecorder) IntrospectionEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectionEndpoint", reflect.TypeOf((*MockConfiguration)(nil).IntrospectionEndpoint))
 }
 
-// IntrospectionEndpointSigningAlgorithmsSupported mocks base method.
+// IntrospectionEndpointSigningAlgorithmsSupported mocks base method
 func (m *MockConfiguration) IntrospectionEndpointSigningAlgorithmsSupported() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IntrospectionEndpointSigningAlgorithmsSupported")
@@ -199,13 +211,13 @@ func (m *MockConfiguration) IntrospectionEndpointSigningAlgorithmsSupported() []
 	return ret0
 }
 
-// IntrospectionEndpointSigningAlgorithmsSupported indicates an expected call of IntrospectionEndpointSigningAlgorithmsSupported.
+// IntrospectionEndpointSigningAlgorithmsSupported indicates an expected call of IntrospectionEndpointSigningAlgorithmsSupported
 func (mr *MockConfigurationMockRecorder) IntrospectionEndpointSigningAlgorithmsSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntrospectionEndpointSigningAlgorithmsSupported", reflect.TypeOf((*MockConfiguration)(nil).IntrospectionEndpointSigningAlgorithmsSupported))
 }
 
-// IssuerFromRequest mocks base method.
+// IssuerFromRequest mocks base method
 func (m *MockConfiguration) IssuerFromRequest(arg0 *http.Request) string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IssuerFromRequest", arg0)
@@ -213,13 +225,13 @@ func (m *MockConfiguration) IssuerFromRequest(arg0 *http.Request) string {
 	return ret0
 }
 
-// IssuerFromRequest indicates an expected call of IssuerFromRequest.
+// IssuerFromRequest indicates an expected call of IssuerFromRequest
 func (mr *MockConfigurationMockRecorder) IssuerFromRequest(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IssuerFromRequest", reflect.TypeOf((*MockConfiguration)(nil).IssuerFromRequest), arg0)
 }
 
-// KeysEndpoint mocks base method.
+// KeysEndpoint mocks base method
 func (m *MockConfiguration) KeysEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "KeysEndpoint")
@@ -227,13 +239,13 @@ func (m *MockConfiguration) KeysEndpoint() op.Endpoint {
 	return ret0
 }
 
-// KeysEndpoint indicates an expected call of KeysEndpoint.
+// KeysEndpoint indicates an expected call of KeysEndpoint
 func (mr *MockConfigurationMockRecorder) KeysEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeysEndpoint", reflect.TypeOf((*MockConfiguration)(nil).KeysEndpoint))
 }
 
-// RequestObjectSigningAlgorithmsSupported mocks base method.
+// RequestObjectSigningAlgorithmsSupported mocks base method
 func (m *MockConfiguration) RequestObjectSigningAlgorithmsSupported() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RequestObjectSigningAlgorithmsSupported")
@@ -241,13 +253,13 @@ func (m *MockConfiguration) RequestObjectSigningAlgorithmsSupported() []string {
 	return ret0
 }
 
-// RequestObjectSigningAlgorithmsSupported indicates an expected call of RequestObjectSigningAlgorithmsSupported.
+// RequestObjectSigningAlgorithmsSupported indicates an expected call of RequestObjectSigningAlgorithmsSupported
 func (mr *MockConfigurationMockRecorder) RequestObjectSigningAlgorithmsSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestObjectSigningAlgorithmsSupported", reflect.TypeOf((*MockConfiguration)(nil).RequestObjectSigningAlgorithmsSupported))
 }
 
-// RequestObjectSupported mocks base method.
+// RequestObjectSupported mocks base method
 func (m *MockConfiguration) RequestObjectSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RequestObjectSupported")
@@ -255,13 +267,13 @@ func (m *MockConfiguration) RequestObjectSupported() bool {
 	return ret0
 }
 
-// RequestObjectSupported indicates an expected call of RequestObjectSupported.
+// RequestObjectSupported indicates an expected call of RequestObjectSupported
 func (mr *MockConfigurationMockRecorder) RequestObjectSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestObjectSupported", reflect.TypeOf((*MockConfiguration)(nil).RequestObjectSupported))
 }
 
-// RevocationAuthMethodPrivateKeyJWTSupported mocks base method.
+// RevocationAuthMethodPrivateKeyJWTSupported mocks base method
 func (m *MockConfiguration) RevocationAuthMethodPrivateKeyJWTSupported() bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RevocationAuthMethodPrivateKeyJWTSupported")
@@ -269,13 +281,13 @@ func (m *MockConfiguration) RevocationAuthMethodPrivateKeyJWTSupported() bool {
 	return ret0
 }
 
-// RevocationAuthMethodPrivateKeyJWTSupported indicates an expected call of RevocationAuthMethodPrivateKeyJWTSupported.
+// RevocationAuthMethodPrivateKeyJWTSupported indicates an expected call of RevocationAuthMethodPrivateKeyJWTSupported
 func (mr *MockConfigurationMockRecorder) RevocationAuthMethodPrivateKeyJWTSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevocationAuthMethodPrivateKeyJWTSupported", reflect.TypeOf((*MockConfiguration)(nil).RevocationAuthMethodPrivateKeyJWTSupported))
 }
 
-// RevocationEndpoint mocks base method.
+// RevocationEndpoint mocks base method
 func (m *MockConfiguration) RevocationEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RevocationEndpoint")
@@ -283,13 +295,13 @@ func (m *MockConfiguration) RevocationEndpoint() op.Endpoint {
 	return ret0
 }
 
-// RevocationEndpoint indicates an expected call of RevocationEndpoint.
+// RevocationEndpoint indicates an expected call of RevocationEndpoint
 func (mr *MockConfigurationMockRecorder) RevocationEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevocationEndpoint", reflect.TypeOf((*MockConfiguration)(nil).RevocationEndpoint))
 }
 
-// RevocationEndpointSigningAlgorithmsSupported mocks base method.
+// RevocationEndpointSigningAlgorithmsSupported mocks base method
 func (m *MockConfiguration) RevocationEndpointSigningAlgorithmsSupported() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RevocationEndpointSigningAlgorithmsSupported")
@@ -297,13 +309,13 @@ func (m *MockConfiguration) RevocationEndpointSigningAlgorithmsSupported() []str
 	return ret0
 }
 
-// RevocationEndpointSigningAlgorithmsSupported indicates an expected call of RevocationEndpointSigningAlgorithmsSupported.
+// RevocationEndpointSigningAlgorithmsSupported indicates an expected call of RevocationEndpointSigningAlgorithmsSupported
 func (mr *MockConfigurationMockRecorder) RevocationEndpointSigningAlgorithmsSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevocationEndpointSigningAlgorithmsSupported", reflect.TypeOf((*MockConfiguration)(nil).RevocationEndpointSigningAlgorithmsSupported))
 }
 
-// SupportedUILocales mocks base method.
+// SupportedUILocales mocks base method
 func (m *MockConfiguration) SupportedUILocales() []language.Tag {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SupportedUILocales")
@@ -311,13 +323,13 @@ func (m *MockConfiguration) SupportedUILocales() []language.Tag {
 	return ret0
 }
 
-// SupportedUILocales indicates an expected call of SupportedUILocales.
+// SupportedUILocales indicates an expected call of SupportedUILocales
 func (mr *MockConfigurationMockRecorder) SupportedUILocales() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SupportedUILocales", reflect.TypeOf((*MockConfiguration)(nil).SupportedUILocales))
 }
 
-// TokenEndpoint mocks base method.
+// TokenEndpoint mocks base method
 func (m *MockConfiguration) TokenEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "TokenEndpoint")
@@ -325,13 +337,13 @@ func (m *MockConfiguration) TokenEndpoint() op.Endpoint {
 	return ret0
 }
 
-// TokenEndpoint indicates an expected call of TokenEndpoint.
+// TokenEndpoint indicates an expected call of TokenEndpoint
 func (mr *MockConfigurationMockRecorder) TokenEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokenEndpoint", reflect.TypeOf((*MockConfiguration)(nil).TokenEndpoint))
 }
 
-// TokenEndpointSigningAlgorithmsSupported mocks base method.
+// TokenEndpointSigningAlgorithmsSupported mocks base method
 func (m *MockConfiguration) TokenEndpointSigningAlgorithmsSupported() []string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "TokenEndpointSigningAlgorithmsSupported")
@@ -339,13 +351,13 @@ func (m *MockConfiguration) TokenEndpointSigningAlgorithmsSupported() []string {
 	return ret0
 }
 
-// TokenEndpointSigningAlgorithmsSupported indicates an expected call of TokenEndpointSigningAlgorithmsSupported.
+// TokenEndpointSigningAlgorithmsSupported indicates an expected call of TokenEndpointSigningAlgorithmsSupported
 func (mr *MockConfigurationMockRecorder) TokenEndpointSigningAlgorithmsSupported() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokenEndpointSigningAlgorithmsSupported", reflect.TypeOf((*MockConfiguration)(nil).TokenEndpointSigningAlgorithmsSupported))
 }
 
-// UserinfoEndpoint mocks base method.
+// UserinfoEndpoint mocks base method
 func (m *MockConfiguration) UserinfoEndpoint() op.Endpoint {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "UserinfoEndpoint")
@@ -353,7 +365,7 @@ func (m *MockConfiguration) UserinfoEndpoint() op.Endpoint {
 	return ret0
 }
 
-// UserinfoEndpoint indicates an expected call of UserinfoEndpoint.
+// UserinfoEndpoint indicates an expected call of UserinfoEndpoint
 func (mr *MockConfigurationMockRecorder) UserinfoEndpoint() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserinfoEndpoint", reflect.TypeOf((*MockConfiguration)(nil).UserinfoEndpoint))
diff --git a/pkg/op/mock/discovery.mock.go b/pkg/op/mock/discovery.mock.go
index 2974c4d..96a643d 100644
--- a/pkg/op/mock/discovery.mock.go
+++ b/pkg/op/mock/discovery.mock.go
@@ -1,41 +1,40 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: DiscoverStorage)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: DiscoverStorage)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
 	context "context"
-	reflect "reflect"
-
 	gomock "github.com/golang/mock/gomock"
 	jose "gopkg.in/square/go-jose.v2"
+	reflect "reflect"
 )
 
-// MockDiscoverStorage is a mock of DiscoverStorage interface.
+// MockDiscoverStorage is a mock of DiscoverStorage interface
 type MockDiscoverStorage struct {
 	ctrl     *gomock.Controller
 	recorder *MockDiscoverStorageMockRecorder
 }
 
-// MockDiscoverStorageMockRecorder is the mock recorder for MockDiscoverStorage.
+// MockDiscoverStorageMockRecorder is the mock recorder for MockDiscoverStorage
 type MockDiscoverStorageMockRecorder struct {
 	mock *MockDiscoverStorage
 }
 
-// NewMockDiscoverStorage creates a new mock instance.
+// NewMockDiscoverStorage creates a new mock instance
 func NewMockDiscoverStorage(ctrl *gomock.Controller) *MockDiscoverStorage {
 	mock := &MockDiscoverStorage{ctrl: ctrl}
 	mock.recorder = &MockDiscoverStorageMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockDiscoverStorage) EXPECT() *MockDiscoverStorageMockRecorder {
 	return m.recorder
 }
 
-// SignatureAlgorithms mocks base method.
+// SignatureAlgorithms mocks base method
 func (m *MockDiscoverStorage) SignatureAlgorithms(arg0 context.Context) ([]jose.SignatureAlgorithm, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SignatureAlgorithms", arg0)
@@ -44,7 +43,7 @@ func (m *MockDiscoverStorage) SignatureAlgorithms(arg0 context.Context) ([]jose.
 	return ret0, ret1
 }
 
-// SignatureAlgorithms indicates an expected call of SignatureAlgorithms.
+// SignatureAlgorithms indicates an expected call of SignatureAlgorithms
 func (mr *MockDiscoverStorageMockRecorder) SignatureAlgorithms(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignatureAlgorithms", reflect.TypeOf((*MockDiscoverStorage)(nil).SignatureAlgorithms), arg0)
diff --git a/pkg/op/mock/generate.go b/pkg/op/mock/generate.go
index 543c6fd..0066571 100644
--- a/pkg/op/mock/generate.go
+++ b/pkg/op/mock/generate.go
@@ -1,9 +1,9 @@
 package mock
 
-//go:generate mockgen -package mock -destination ./storage.mock.go github.com/zitadel/oidc/pkg/op Storage
-//go:generate mockgen -package mock -destination ./authorizer.mock.go github.com/zitadel/oidc/pkg/op Authorizer
-//go:generate mockgen -package mock -destination ./client.mock.go github.com/zitadel/oidc/pkg/op Client
-//go:generate mockgen -package mock -destination ./configuration.mock.go github.com/zitadel/oidc/pkg/op Configuration
-//go:generate mockgen -package mock -destination ./discovery.mock.go github.com/zitadel/oidc/pkg/op DiscoverStorage
-//go:generate mockgen -package mock -destination ./signer.mock.go github.com/zitadel/oidc/pkg/op SigningKey,Key
-//go:generate mockgen -package mock -destination ./key.mock.go github.com/zitadel/oidc/pkg/op KeyProvider
+//go:generate mockgen -package mock -destination ./storage.mock.go github.com/zitadel/oidc/v2/pkg/op Storage
+//go:generate mockgen -package mock -destination ./authorizer.mock.go github.com/zitadel/oidc/v2/pkg/op Authorizer
+//go:generate mockgen -package mock -destination ./client.mock.go github.com/zitadel/oidc/v2/pkg/op Client
+//go:generate mockgen -package mock -destination ./configuration.mock.go github.com/zitadel/oidc/v2/pkg/op Configuration
+//go:generate mockgen -package mock -destination ./discovery.mock.go github.com/zitadel/oidc/v2/pkg/op DiscoverStorage
+//go:generate mockgen -package mock -destination ./signer.mock.go github.com/zitadel/oidc/v2/pkg/op SigningKey,Key
+//go:generate mockgen -package mock -destination ./key.mock.go github.com/zitadel/oidc/v2/pkg/op KeyProvider
diff --git a/pkg/op/mock/key.mock.go b/pkg/op/mock/key.mock.go
index a72f412..2dc584e 100644
--- a/pkg/op/mock/key.mock.go
+++ b/pkg/op/mock/key.mock.go
@@ -1,42 +1,40 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: KeyProvider)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: KeyProvider)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
 	context "context"
-	reflect "reflect"
-
 	gomock "github.com/golang/mock/gomock"
-
 	op "github.com/zitadel/oidc/v2/pkg/op"
+	reflect "reflect"
 )
 
-// MockKeyProvider is a mock of KeyProvider interface.
+// MockKeyProvider is a mock of KeyProvider interface
 type MockKeyProvider struct {
 	ctrl     *gomock.Controller
 	recorder *MockKeyProviderMockRecorder
 }
 
-// MockKeyProviderMockRecorder is the mock recorder for MockKeyProvider.
+// MockKeyProviderMockRecorder is the mock recorder for MockKeyProvider
 type MockKeyProviderMockRecorder struct {
 	mock *MockKeyProvider
 }
 
-// NewMockKeyProvider creates a new mock instance.
+// NewMockKeyProvider creates a new mock instance
 func NewMockKeyProvider(ctrl *gomock.Controller) *MockKeyProvider {
 	mock := &MockKeyProvider{ctrl: ctrl}
 	mock.recorder = &MockKeyProviderMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockKeyProvider) EXPECT() *MockKeyProviderMockRecorder {
 	return m.recorder
 }
 
-// KeySet mocks base method.
+// KeySet mocks base method
 func (m *MockKeyProvider) KeySet(arg0 context.Context) ([]op.Key, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "KeySet", arg0)
@@ -45,7 +43,7 @@ func (m *MockKeyProvider) KeySet(arg0 context.Context) ([]op.Key, error) {
 	return ret0, ret1
 }
 
-// KeySet indicates an expected call of KeySet.
+// KeySet indicates an expected call of KeySet
 func (mr *MockKeyProviderMockRecorder) KeySet(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeySet", reflect.TypeOf((*MockKeyProvider)(nil).KeySet), arg0)
diff --git a/pkg/op/mock/signer.mock.go b/pkg/op/mock/signer.mock.go
index 35fd8dd..56072cb 100644
--- a/pkg/op/mock/signer.mock.go
+++ b/pkg/op/mock/signer.mock.go
@@ -1,40 +1,39 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: SigningKey,Key)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: SigningKey,Key)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
-	reflect "reflect"
-
 	gomock "github.com/golang/mock/gomock"
 	jose "gopkg.in/square/go-jose.v2"
+	reflect "reflect"
 )
 
-// MockSigningKey is a mock of SigningKey interface.
+// MockSigningKey is a mock of SigningKey interface
 type MockSigningKey struct {
 	ctrl     *gomock.Controller
 	recorder *MockSigningKeyMockRecorder
 }
 
-// MockSigningKeyMockRecorder is the mock recorder for MockSigningKey.
+// MockSigningKeyMockRecorder is the mock recorder for MockSigningKey
 type MockSigningKeyMockRecorder struct {
 	mock *MockSigningKey
 }
 
-// NewMockSigningKey creates a new mock instance.
+// NewMockSigningKey creates a new mock instance
 func NewMockSigningKey(ctrl *gomock.Controller) *MockSigningKey {
 	mock := &MockSigningKey{ctrl: ctrl}
 	mock.recorder = &MockSigningKeyMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockSigningKey) EXPECT() *MockSigningKeyMockRecorder {
 	return m.recorder
 }
 
-// ID mocks base method.
+// ID mocks base method
 func (m *MockSigningKey) ID() string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ID")
@@ -42,13 +41,13 @@ func (m *MockSigningKey) ID() string {
 	return ret0
 }
 
-// ID indicates an expected call of ID.
+// ID indicates an expected call of ID
 func (mr *MockSigningKeyMockRecorder) ID() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockSigningKey)(nil).ID))
 }
 
-// Key mocks base method.
+// Key mocks base method
 func (m *MockSigningKey) Key() interface{} {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Key")
@@ -56,13 +55,13 @@ func (m *MockSigningKey) Key() interface{} {
 	return ret0
 }
 
-// Key indicates an expected call of Key.
+// Key indicates an expected call of Key
 func (mr *MockSigningKeyMockRecorder) Key() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Key", reflect.TypeOf((*MockSigningKey)(nil).Key))
 }
 
-// SignatureAlgorithm mocks base method.
+// SignatureAlgorithm mocks base method
 func (m *MockSigningKey) SignatureAlgorithm() jose.SignatureAlgorithm {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SignatureAlgorithm")
@@ -70,36 +69,36 @@ func (m *MockSigningKey) SignatureAlgorithm() jose.SignatureAlgorithm {
 	return ret0
 }
 
-// SignatureAlgorithm indicates an expected call of SignatureAlgorithm.
+// SignatureAlgorithm indicates an expected call of SignatureAlgorithm
 func (mr *MockSigningKeyMockRecorder) SignatureAlgorithm() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignatureAlgorithm", reflect.TypeOf((*MockSigningKey)(nil).SignatureAlgorithm))
 }
 
-// MockKey is a mock of Key interface.
+// MockKey is a mock of Key interface
 type MockKey struct {
 	ctrl     *gomock.Controller
 	recorder *MockKeyMockRecorder
 }
 
-// MockKeyMockRecorder is the mock recorder for MockKey.
+// MockKeyMockRecorder is the mock recorder for MockKey
 type MockKeyMockRecorder struct {
 	mock *MockKey
 }
 
-// NewMockKey creates a new mock instance.
+// NewMockKey creates a new mock instance
 func NewMockKey(ctrl *gomock.Controller) *MockKey {
 	mock := &MockKey{ctrl: ctrl}
 	mock.recorder = &MockKeyMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockKey) EXPECT() *MockKeyMockRecorder {
 	return m.recorder
 }
 
-// Algorithm mocks base method.
+// Algorithm mocks base method
 func (m *MockKey) Algorithm() jose.SignatureAlgorithm {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Algorithm")
@@ -107,13 +106,13 @@ func (m *MockKey) Algorithm() jose.SignatureAlgorithm {
 	return ret0
 }
 
-// Algorithm indicates an expected call of Algorithm.
+// Algorithm indicates an expected call of Algorithm
 func (mr *MockKeyMockRecorder) Algorithm() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Algorithm", reflect.TypeOf((*MockKey)(nil).Algorithm))
 }
 
-// ID mocks base method.
+// ID mocks base method
 func (m *MockKey) ID() string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ID")
@@ -121,13 +120,13 @@ func (m *MockKey) ID() string {
 	return ret0
 }
 
-// ID indicates an expected call of ID.
+// ID indicates an expected call of ID
 func (mr *MockKeyMockRecorder) ID() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockKey)(nil).ID))
 }
 
-// Key mocks base method.
+// Key mocks base method
 func (m *MockKey) Key() interface{} {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Key")
@@ -135,13 +134,13 @@ func (m *MockKey) Key() interface{} {
 	return ret0
 }
 
-// Key indicates an expected call of Key.
+// Key indicates an expected call of Key
 func (mr *MockKeyMockRecorder) Key() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Key", reflect.TypeOf((*MockKey)(nil).Key))
 }
 
-// Use mocks base method.
+// Use mocks base method
 func (m *MockKey) Use() string {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Use")
@@ -149,7 +148,7 @@ func (m *MockKey) Use() string {
 	return ret0
 }
 
-// Use indicates an expected call of Use.
+// Use indicates an expected call of Use
 func (mr *MockKeyMockRecorder) Use() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Use", reflect.TypeOf((*MockKey)(nil).Use))
diff --git a/pkg/op/mock/storage.mock.go b/pkg/op/mock/storage.mock.go
index db38abb..1ade527 100644
--- a/pkg/op/mock/storage.mock.go
+++ b/pkg/op/mock/storage.mock.go
@@ -1,45 +1,43 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/zitadel/oidc/pkg/op (interfaces: Storage)
+// Source: github.com/zitadel/oidc/v2/pkg/op (interfaces: Storage)
 
 // Package mock is a generated GoMock package.
 package mock
 
 import (
 	context "context"
-	reflect "reflect"
-	time "time"
-
 	gomock "github.com/golang/mock/gomock"
-	jose "gopkg.in/square/go-jose.v2"
-
 	oidc "github.com/zitadel/oidc/v2/pkg/oidc"
 	op "github.com/zitadel/oidc/v2/pkg/op"
+	jose "gopkg.in/square/go-jose.v2"
+	reflect "reflect"
+	time "time"
 )
 
-// MockStorage is a mock of Storage interface.
+// MockStorage is a mock of Storage interface
 type MockStorage struct {
 	ctrl     *gomock.Controller
 	recorder *MockStorageMockRecorder
 }
 
-// MockStorageMockRecorder is the mock recorder for MockStorage.
+// MockStorageMockRecorder is the mock recorder for MockStorage
 type MockStorageMockRecorder struct {
 	mock *MockStorage
 }
 
-// NewMockStorage creates a new mock instance.
+// NewMockStorage creates a new mock instance
 func NewMockStorage(ctrl *gomock.Controller) *MockStorage {
 	mock := &MockStorage{ctrl: ctrl}
 	mock.recorder = &MockStorageMockRecorder{mock}
 	return mock
 }
 
-// EXPECT returns an object that allows the caller to indicate expected use.
+// EXPECT returns an object that allows the caller to indicate expected use
 func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
 	return m.recorder
 }
 
-// AuthRequestByCode mocks base method.
+// AuthRequestByCode mocks base method
 func (m *MockStorage) AuthRequestByCode(arg0 context.Context, arg1 string) (op.AuthRequest, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthRequestByCode", arg0, arg1)
@@ -48,13 +46,13 @@ func (m *MockStorage) AuthRequestByCode(arg0 context.Context, arg1 string) (op.A
 	return ret0, ret1
 }
 
-// AuthRequestByCode indicates an expected call of AuthRequestByCode.
+// AuthRequestByCode indicates an expected call of AuthRequestByCode
 func (mr *MockStorageMockRecorder) AuthRequestByCode(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthRequestByCode", reflect.TypeOf((*MockStorage)(nil).AuthRequestByCode), arg0, arg1)
 }
 
-// AuthRequestByID mocks base method.
+// AuthRequestByID mocks base method
 func (m *MockStorage) AuthRequestByID(arg0 context.Context, arg1 string) (op.AuthRequest, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthRequestByID", arg0, arg1)
@@ -63,13 +61,13 @@ func (m *MockStorage) AuthRequestByID(arg0 context.Context, arg1 string) (op.Aut
 	return ret0, ret1
 }
 
-// AuthRequestByID indicates an expected call of AuthRequestByID.
+// AuthRequestByID indicates an expected call of AuthRequestByID
 func (mr *MockStorageMockRecorder) AuthRequestByID(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthRequestByID", reflect.TypeOf((*MockStorage)(nil).AuthRequestByID), arg0, arg1)
 }
 
-// AuthorizeClientIDSecret mocks base method.
+// AuthorizeClientIDSecret mocks base method
 func (m *MockStorage) AuthorizeClientIDSecret(arg0 context.Context, arg1, arg2 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "AuthorizeClientIDSecret", arg0, arg1, arg2)
@@ -77,13 +75,13 @@ func (m *MockStorage) AuthorizeClientIDSecret(arg0 context.Context, arg1, arg2 s
 	return ret0
 }
 
-// AuthorizeClientIDSecret indicates an expected call of AuthorizeClientIDSecret.
+// AuthorizeClientIDSecret indicates an expected call of AuthorizeClientIDSecret
 func (mr *MockStorageMockRecorder) AuthorizeClientIDSecret(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeClientIDSecret", reflect.TypeOf((*MockStorage)(nil).AuthorizeClientIDSecret), arg0, arg1, arg2)
 }
 
-// CreateAccessAndRefreshTokens mocks base method.
+// CreateAccessAndRefreshTokens mocks base method
 func (m *MockStorage) CreateAccessAndRefreshTokens(arg0 context.Context, arg1 op.TokenRequest, arg2 string) (string, string, time.Time, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "CreateAccessAndRefreshTokens", arg0, arg1, arg2)
@@ -94,13 +92,13 @@ func (m *MockStorage) CreateAccessAndRefreshTokens(arg0 context.Context, arg1 op
 	return ret0, ret1, ret2, ret3
 }
 
-// CreateAccessAndRefreshTokens indicates an expected call of CreateAccessAndRefreshTokens.
+// CreateAccessAndRefreshTokens indicates an expected call of CreateAccessAndRefreshTokens
 func (mr *MockStorageMockRecorder) CreateAccessAndRefreshTokens(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessAndRefreshTokens", reflect.TypeOf((*MockStorage)(nil).CreateAccessAndRefreshTokens), arg0, arg1, arg2)
 }
 
-// CreateAccessToken mocks base method.
+// CreateAccessToken mocks base method
 func (m *MockStorage) CreateAccessToken(arg0 context.Context, arg1 op.TokenRequest) (string, time.Time, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "CreateAccessToken", arg0, arg1)
@@ -110,13 +108,13 @@ func (m *MockStorage) CreateAccessToken(arg0 context.Context, arg1 op.TokenReque
 	return ret0, ret1, ret2
 }
 
-// CreateAccessToken indicates an expected call of CreateAccessToken.
+// CreateAccessToken indicates an expected call of CreateAccessToken
 func (mr *MockStorageMockRecorder) CreateAccessToken(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessToken", reflect.TypeOf((*MockStorage)(nil).CreateAccessToken), arg0, arg1)
 }
 
-// CreateAuthRequest mocks base method.
+// CreateAuthRequest mocks base method
 func (m *MockStorage) CreateAuthRequest(arg0 context.Context, arg1 *oidc.AuthRequest, arg2 string) (op.AuthRequest, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "CreateAuthRequest", arg0, arg1, arg2)
@@ -125,13 +123,13 @@ func (m *MockStorage) CreateAuthRequest(arg0 context.Context, arg1 *oidc.AuthReq
 	return ret0, ret1
 }
 
-// CreateAuthRequest indicates an expected call of CreateAuthRequest.
+// CreateAuthRequest indicates an expected call of CreateAuthRequest
 func (mr *MockStorageMockRecorder) CreateAuthRequest(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthRequest", reflect.TypeOf((*MockStorage)(nil).CreateAuthRequest), arg0, arg1, arg2)
 }
 
-// DeleteAuthRequest mocks base method.
+// DeleteAuthRequest mocks base method
 func (m *MockStorage) DeleteAuthRequest(arg0 context.Context, arg1 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "DeleteAuthRequest", arg0, arg1)
@@ -139,13 +137,13 @@ func (m *MockStorage) DeleteAuthRequest(arg0 context.Context, arg1 string) error
 	return ret0
 }
 
-// DeleteAuthRequest indicates an expected call of DeleteAuthRequest.
+// DeleteAuthRequest indicates an expected call of DeleteAuthRequest
 func (mr *MockStorageMockRecorder) DeleteAuthRequest(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAuthRequest", reflect.TypeOf((*MockStorage)(nil).DeleteAuthRequest), arg0, arg1)
 }
 
-// GetClientByClientID mocks base method.
+// GetClientByClientID mocks base method
 func (m *MockStorage) GetClientByClientID(arg0 context.Context, arg1 string) (op.Client, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetClientByClientID", arg0, arg1)
@@ -154,13 +152,13 @@ func (m *MockStorage) GetClientByClientID(arg0 context.Context, arg1 string) (op
 	return ret0, ret1
 }
 
-// GetClientByClientID indicates an expected call of GetClientByClientID.
+// GetClientByClientID indicates an expected call of GetClientByClientID
 func (mr *MockStorageMockRecorder) GetClientByClientID(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClientByClientID", reflect.TypeOf((*MockStorage)(nil).GetClientByClientID), arg0, arg1)
 }
 
-// GetKeyByIDAndUserID mocks base method.
+// GetKeyByIDAndUserID mocks base method
 func (m *MockStorage) GetKeyByIDAndUserID(arg0 context.Context, arg1, arg2 string) (*jose.JSONWebKey, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetKeyByIDAndUserID", arg0, arg1, arg2)
@@ -169,13 +167,13 @@ func (m *MockStorage) GetKeyByIDAndUserID(arg0 context.Context, arg1, arg2 strin
 	return ret0, ret1
 }
 
-// GetKeyByIDAndUserID indicates an expected call of GetKeyByIDAndUserID.
+// GetKeyByIDAndUserID indicates an expected call of GetKeyByIDAndUserID
 func (mr *MockStorageMockRecorder) GetKeyByIDAndUserID(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKeyByIDAndUserID", reflect.TypeOf((*MockStorage)(nil).GetKeyByIDAndUserID), arg0, arg1, arg2)
 }
 
-// GetPrivateClaimsFromScopes mocks base method.
+// GetPrivateClaimsFromScopes mocks base method
 func (m *MockStorage) GetPrivateClaimsFromScopes(arg0 context.Context, arg1, arg2 string, arg3 []string) (map[string]interface{}, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetPrivateClaimsFromScopes", arg0, arg1, arg2, arg3)
@@ -184,13 +182,13 @@ func (m *MockStorage) GetPrivateClaimsFromScopes(arg0 context.Context, arg1, arg
 	return ret0, ret1
 }
 
-// GetPrivateClaimsFromScopes indicates an expected call of GetPrivateClaimsFromScopes.
+// GetPrivateClaimsFromScopes indicates an expected call of GetPrivateClaimsFromScopes
 func (mr *MockStorageMockRecorder) GetPrivateClaimsFromScopes(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPrivateClaimsFromScopes", reflect.TypeOf((*MockStorage)(nil).GetPrivateClaimsFromScopes), arg0, arg1, arg2, arg3)
 }
 
-// Health mocks base method.
+// Health mocks base method
 func (m *MockStorage) Health(arg0 context.Context) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Health", arg0)
@@ -198,13 +196,13 @@ func (m *MockStorage) Health(arg0 context.Context) error {
 	return ret0
 }
 
-// Health indicates an expected call of Health.
+// Health indicates an expected call of Health
 func (mr *MockStorageMockRecorder) Health(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockStorage)(nil).Health), arg0)
 }
 
-// KeySet mocks base method.
+// KeySet mocks base method
 func (m *MockStorage) KeySet(arg0 context.Context) ([]op.Key, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "KeySet", arg0)
@@ -213,13 +211,13 @@ func (m *MockStorage) KeySet(arg0 context.Context) ([]op.Key, error) {
 	return ret0, ret1
 }
 
-// KeySet indicates an expected call of KeySet.
+// KeySet indicates an expected call of KeySet
 func (mr *MockStorageMockRecorder) KeySet(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeySet", reflect.TypeOf((*MockStorage)(nil).KeySet), arg0)
 }
 
-// RevokeToken mocks base method.
+// RevokeToken mocks base method
 func (m *MockStorage) RevokeToken(arg0 context.Context, arg1, arg2, arg3 string) *oidc.Error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RevokeToken", arg0, arg1, arg2, arg3)
@@ -227,13 +225,13 @@ func (m *MockStorage) RevokeToken(arg0 context.Context, arg1, arg2, arg3 string)
 	return ret0
 }
 
-// RevokeToken indicates an expected call of RevokeToken.
+// RevokeToken indicates an expected call of RevokeToken
 func (mr *MockStorageMockRecorder) RevokeToken(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeToken", reflect.TypeOf((*MockStorage)(nil).RevokeToken), arg0, arg1, arg2, arg3)
 }
 
-// SaveAuthCode mocks base method.
+// SaveAuthCode mocks base method
 func (m *MockStorage) SaveAuthCode(arg0 context.Context, arg1, arg2 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SaveAuthCode", arg0, arg1, arg2)
@@ -241,13 +239,13 @@ func (m *MockStorage) SaveAuthCode(arg0 context.Context, arg1, arg2 string) erro
 	return ret0
 }
 
-// SaveAuthCode indicates an expected call of SaveAuthCode.
+// SaveAuthCode indicates an expected call of SaveAuthCode
 func (mr *MockStorageMockRecorder) SaveAuthCode(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthCode", reflect.TypeOf((*MockStorage)(nil).SaveAuthCode), arg0, arg1, arg2)
 }
 
-// SetIntrospectionFromToken mocks base method.
+// SetIntrospectionFromToken mocks base method
 func (m *MockStorage) SetIntrospectionFromToken(arg0 context.Context, arg1 oidc.IntrospectionResponse, arg2, arg3, arg4 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SetIntrospectionFromToken", arg0, arg1, arg2, arg3, arg4)
@@ -255,13 +253,13 @@ func (m *MockStorage) SetIntrospectionFromToken(arg0 context.Context, arg1 oidc.
 	return ret0
 }
 
-// SetIntrospectionFromToken indicates an expected call of SetIntrospectionFromToken.
+// SetIntrospectionFromToken indicates an expected call of SetIntrospectionFromToken
 func (mr *MockStorageMockRecorder) SetIntrospectionFromToken(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIntrospectionFromToken", reflect.TypeOf((*MockStorage)(nil).SetIntrospectionFromToken), arg0, arg1, arg2, arg3, arg4)
 }
 
-// SetUserinfoFromScopes mocks base method.
+// SetUserinfoFromScopes mocks base method
 func (m *MockStorage) SetUserinfoFromScopes(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3 string, arg4 []string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SetUserinfoFromScopes", arg0, arg1, arg2, arg3, arg4)
@@ -269,13 +267,13 @@ func (m *MockStorage) SetUserinfoFromScopes(arg0 context.Context, arg1 oidc.User
 	return ret0
 }
 
-// SetUserinfoFromScopes indicates an expected call of SetUserinfoFromScopes.
+// SetUserinfoFromScopes indicates an expected call of SetUserinfoFromScopes
 func (mr *MockStorageMockRecorder) SetUserinfoFromScopes(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromScopes", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromScopes), arg0, arg1, arg2, arg3, arg4)
 }
 
-// SetUserinfoFromToken mocks base method.
+// SetUserinfoFromToken mocks base method
 func (m *MockStorage) SetUserinfoFromToken(arg0 context.Context, arg1 oidc.UserInfoSetter, arg2, arg3, arg4 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SetUserinfoFromToken", arg0, arg1, arg2, arg3, arg4)
@@ -283,13 +281,13 @@ func (m *MockStorage) SetUserinfoFromToken(arg0 context.Context, arg1 oidc.UserI
 	return ret0
 }
 
-// SetUserinfoFromToken indicates an expected call of SetUserinfoFromToken.
+// SetUserinfoFromToken indicates an expected call of SetUserinfoFromToken
 func (mr *MockStorageMockRecorder) SetUserinfoFromToken(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserinfoFromToken", reflect.TypeOf((*MockStorage)(nil).SetUserinfoFromToken), arg0, arg1, arg2, arg3, arg4)
 }
 
-// SignatureAlgorithms mocks base method.
+// SignatureAlgorithms mocks base method
 func (m *MockStorage) SignatureAlgorithms(arg0 context.Context) ([]jose.SignatureAlgorithm, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SignatureAlgorithms", arg0)
@@ -298,13 +296,13 @@ func (m *MockStorage) SignatureAlgorithms(arg0 context.Context) ([]jose.Signatur
 	return ret0, ret1
 }
 
-// SignatureAlgorithms indicates an expected call of SignatureAlgorithms.
+// SignatureAlgorithms indicates an expected call of SignatureAlgorithms
 func (mr *MockStorageMockRecorder) SignatureAlgorithms(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignatureAlgorithms", reflect.TypeOf((*MockStorage)(nil).SignatureAlgorithms), arg0)
 }
 
-// SigningKey mocks base method.
+// SigningKey mocks base method
 func (m *MockStorage) SigningKey(arg0 context.Context) (op.SigningKey, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SigningKey", arg0)
@@ -313,13 +311,13 @@ func (m *MockStorage) SigningKey(arg0 context.Context) (op.SigningKey, error) {
 	return ret0, ret1
 }
 
-// SigningKey indicates an expected call of SigningKey.
+// SigningKey indicates an expected call of SigningKey
 func (mr *MockStorageMockRecorder) SigningKey(arg0 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SigningKey", reflect.TypeOf((*MockStorage)(nil).SigningKey), arg0)
 }
 
-// TerminateSession mocks base method.
+// TerminateSession mocks base method
 func (m *MockStorage) TerminateSession(arg0 context.Context, arg1, arg2 string) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "TerminateSession", arg0, arg1, arg2)
@@ -327,13 +325,13 @@ func (m *MockStorage) TerminateSession(arg0 context.Context, arg1, arg2 string)
 	return ret0
 }
 
-// TerminateSession indicates an expected call of TerminateSession.
+// TerminateSession indicates an expected call of TerminateSession
 func (mr *MockStorageMockRecorder) TerminateSession(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TerminateSession", reflect.TypeOf((*MockStorage)(nil).TerminateSession), arg0, arg1, arg2)
 }
 
-// TokenRequestByRefreshToken mocks base method.
+// TokenRequestByRefreshToken mocks base method
 func (m *MockStorage) TokenRequestByRefreshToken(arg0 context.Context, arg1 string) (op.RefreshTokenRequest, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "TokenRequestByRefreshToken", arg0, arg1)
@@ -342,13 +340,13 @@ func (m *MockStorage) TokenRequestByRefreshToken(arg0 context.Context, arg1 stri
 	return ret0, ret1
 }
 
-// TokenRequestByRefreshToken indicates an expected call of TokenRequestByRefreshToken.
+// TokenRequestByRefreshToken indicates an expected call of TokenRequestByRefreshToken
 func (mr *MockStorageMockRecorder) TokenRequestByRefreshToken(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokenRequestByRefreshToken", reflect.TypeOf((*MockStorage)(nil).TokenRequestByRefreshToken), arg0, arg1)
 }
 
-// ValidateJWTProfileScopes mocks base method.
+// ValidateJWTProfileScopes mocks base method
 func (m *MockStorage) ValidateJWTProfileScopes(arg0 context.Context, arg1 string, arg2 []string) ([]string, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ValidateJWTProfileScopes", arg0, arg1, arg2)
@@ -357,7 +355,7 @@ func (m *MockStorage) ValidateJWTProfileScopes(arg0 context.Context, arg1 string
 	return ret0, ret1
 }
 
-// ValidateJWTProfileScopes indicates an expected call of ValidateJWTProfileScopes.
+// ValidateJWTProfileScopes indicates an expected call of ValidateJWTProfileScopes
 func (mr *MockStorageMockRecorder) ValidateJWTProfileScopes(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateJWTProfileScopes", reflect.TypeOf((*MockStorage)(nil).ValidateJWTProfileScopes), arg0, arg1, arg2)
diff --git a/pkg/op/op.go b/pkg/op/op.go
index d41a602..69fc851 100644
--- a/pkg/op/op.go
+++ b/pkg/op/op.go
@@ -256,6 +256,11 @@ func (o *Provider) IntrospectionEndpointSigningAlgorithmsSupported() []string {
 	return []string{"RS256"}
 }
 
+func (o *Provider) GrantTypeClientCredentialsSupported() bool {
+	_, ok := o.storage.(ClientCredentialsStorage)
+	return ok
+}
+
 func (o *Provider) RevocationAuthMethodPrivateKeyJWTSupported() bool {
 	return true
 }
diff --git a/pkg/op/storage.go b/pkg/op/storage.go
index b15bec0..f34ff15 100644
--- a/pkg/op/storage.go
+++ b/pkg/op/storage.go
@@ -28,6 +28,11 @@ type AuthStorage interface {
 	KeySet(context.Context) ([]Key, error)
 }
 
+type ClientCredentialsStorage interface {
+	ClientCredentials(ctx context.Context, clientID, clientSecret string) (Client, error)
+	ClientCredentialsTokenRequest(ctx context.Context, clientID string, scopes []string) (TokenRequest, error)
+}
+
 type OPStorage interface {
 	GetClientByClientID(ctx context.Context, clientID string) (Client, error)
 	AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string) error
diff --git a/pkg/op/token_client_credentials.go b/pkg/op/token_client_credentials.go
new file mode 100644
index 0000000..fc31d57
--- /dev/null
+++ b/pkg/op/token_client_credentials.go
@@ -0,0 +1,111 @@
+package op
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+
+	httphelper "github.com/zitadel/oidc/v2/pkg/http"
+	"github.com/zitadel/oidc/v2/pkg/oidc"
+)
+
+// ClientCredentialsExchange handles the OAuth 2.0 client_credentials grant, including
+// parsing, validating, authorizing the client and finally returning a token
+func ClientCredentialsExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
+	request, err := ParseClientCredentialsRequest(r, exchanger.Decoder())
+	if err != nil {
+		RequestError(w, r, err)
+	}
+
+	validatedRequest, client, err := ValidateClientCredentialsRequest(r.Context(), request, exchanger)
+	if err != nil {
+		RequestError(w, r, err)
+		return
+	}
+
+	resp, err := CreateClientCredentialsTokenResponse(r.Context(), validatedRequest, exchanger, client)
+	if err != nil {
+		RequestError(w, r, err)
+		return
+	}
+
+	httphelper.MarshalJSON(w, resp)
+}
+
+// ParseClientCredentialsRequest parsed the http request into a oidc.ClientCredentialsRequest
+func ParseClientCredentialsRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.ClientCredentialsRequest, error) {
+	err := r.ParseForm()
+	if err != nil {
+		return nil, oidc.ErrInvalidRequest().WithDescription("error parsing form").WithParent(err)
+	}
+
+	request := new(oidc.ClientCredentialsRequest)
+	err = decoder.Decode(request, r.Form)
+	if err != nil {
+		return nil, oidc.ErrInvalidRequest().WithDescription("error decoding form").WithParent(err)
+	}
+
+	if clientID, clientSecret, ok := r.BasicAuth(); ok {
+		clientID, err = url.QueryUnescape(clientID)
+		if err != nil {
+			return nil, oidc.ErrInvalidClient().WithDescription("invalid basic auth header").WithParent(err)
+		}
+
+		clientSecret, err = url.QueryUnescape(clientSecret)
+		if err != nil {
+			return nil, oidc.ErrInvalidClient().WithDescription("invalid basic auth header").WithParent(err)
+		}
+
+		request.ClientID = clientID
+		request.ClientSecret = clientSecret
+	}
+
+	return request, nil
+}
+
+// ValidateClientCredentialsRequest validates the client_credentials request parameters including authorization check of the client
+// and returns a TokenRequest and Client implementation to be used in the client_credentials response, resp. creation of the corresponding access_token.
+func ValidateClientCredentialsRequest(ctx context.Context, request *oidc.ClientCredentialsRequest, exchanger Exchanger) (TokenRequest, Client, error) {
+	storage, ok := exchanger.Storage().(ClientCredentialsStorage)
+	if !ok {
+		return nil, nil, oidc.ErrUnsupportedGrantType().WithDescription("client_credentials grant not supported")
+	}
+
+	client, err := AuthorizeClientCredentialsClient(ctx, request, storage)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	tokenRequest, err := storage.ClientCredentialsTokenRequest(ctx, request.ClientID, request.Scope)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return tokenRequest, client, nil
+}
+
+func AuthorizeClientCredentialsClient(ctx context.Context, request *oidc.ClientCredentialsRequest, storage ClientCredentialsStorage) (Client, error) {
+	client, err := storage.ClientCredentials(ctx, request.ClientID, request.ClientSecret)
+	if err != nil {
+		return nil, oidc.ErrInvalidClient().WithParent(err)
+	}
+
+	if !ValidateGrantType(client, oidc.GrantTypeClientCredentials) {
+		return nil, oidc.ErrUnauthorizedClient()
+	}
+
+	return client, nil
+}
+
+func CreateClientCredentialsTokenResponse(ctx context.Context, tokenRequest TokenRequest, creator TokenCreator, client Client) (*oidc.AccessTokenResponse, error) {
+	accessToken, _, validity, err := CreateAccessToken(ctx, tokenRequest, client.AccessTokenType(), creator, client, "")
+	if err != nil {
+		return nil, err
+	}
+
+	return &oidc.AccessTokenResponse{
+		AccessToken: accessToken,
+		TokenType:   oidc.BearerToken,
+		ExpiresIn:   uint64(validity.Seconds()),
+	}, nil
+}
diff --git a/pkg/op/token_request.go b/pkg/op/token_request.go
index f7d9b93..ade6130 100644
--- a/pkg/op/token_request.go
+++ b/pkg/op/token_request.go
@@ -18,6 +18,7 @@ type Exchanger interface {
 	GrantTypeRefreshTokenSupported() bool
 	GrantTypeTokenExchangeSupported() bool
 	GrantTypeJWTAuthorizationSupported() bool
+	GrantTypeClientCredentialsSupported() bool
 }
 
 func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Request) {
@@ -42,6 +43,11 @@ func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Reque
 				TokenExchange(w, r, exchanger)
 				return
 			}
+		case string(oidc.GrantTypeClientCredentials):
+			if exchanger.GrantTypeClientCredentialsSupported() {
+				ClientCredentialsExchange(w, r, exchanger)
+				return
+			}
 		case "":
 			RequestError(w, r, oidc.ErrInvalidRequest().WithDescription("grant_type missing"))
 			return


Test patch:
diff --git a/pkg/op/discovery_test.go b/pkg/op/discovery_test.go
index 66fb4a5..e1b07dd 100644
--- a/pkg/op/discovery_test.go
+++ b/pkg/op/discovery_test.go
@@ -130,6 +130,7 @@ func Test_GrantTypes(t *testing.T) {
 					c.EXPECT().GrantTypeRefreshTokenSupported().Return(false)
 					c.EXPECT().GrantTypeTokenExchangeSupported().Return(false)
 					c.EXPECT().GrantTypeJWTAuthorizationSupported().Return(false)
+					c.EXPECT().GrantTypeClientCredentialsSupported().Return(false)
 					return c
 				}(),
 			},
@@ -139,13 +140,14 @@ func Test_GrantTypes(t *testing.T) {
 			},
 		},
 		{
-			"code, implicit flow, refresh token, token exchange, jwt profile",
+			"code, implicit flow, refresh token, token exchange, jwt profile, client_credentials",
 			args{
 				func() op.Configuration {
 					c := mock.NewMockConfiguration(gomock.NewController(t))
 					c.EXPECT().GrantTypeRefreshTokenSupported().Return(true)
 					c.EXPECT().GrantTypeTokenExchangeSupported().Return(true)
 					c.EXPECT().GrantTypeJWTAuthorizationSupported().Return(true)
+					c.EXPECT().GrantTypeClientCredentialsSupported().Return(true)
 					return c
 				}(),
 			},
@@ -153,6 +155,7 @@ func Test_GrantTypes(t *testing.T) {
 				oidc.GrantTypeCode,
 				oidc.GrantTypeImplicit,
 				oidc.GrantTypeRefreshToken,
+				oidc.GrantTypeClientCredentials,
 				oidc.GrantTypeTokenExchange,
 				oidc.GrantTypeBearer,
 			},