From 219a7c068fa0ec423923f157553f430c80934c45 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Fri, 4 Aug 2023 10:57:36 +0200 Subject: [PATCH] feat: add support for OIDC VC (#3575) This adds initial support for issuing verifiable credentials as specified in https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. Because the spec is still in draft, public identifiers are suffixed with `draft_00`. --- aead/xchacha20.go | 6 + client/manager_test_helpers.go | 11 +- driver/config/provider.go | 6 + driver/config/provider_fosite.go | 6 + driver/registry_base.go | 2 +- flow/flow_test.go | 3 +- fositex/config.go | 3 +- go.mod | 26 +- go.sum | 49 +- internal/httpclient/.openapi-generator/FILES | 12 + internal/httpclient/README.md | 7 + internal/httpclient/api/openapi.yaml | 201 ++++++++ internal/httpclient/api_oidc.go | 130 +++++ .../CreateVerifiableCredentialRequestBody.md | 108 +++++ .../docs/CredentialSupportedDraft00.md | 134 ++++++ internal/httpclient/docs/OidcApi.md | 67 +++ internal/httpclient/docs/OidcConfiguration.md | 52 ++ internal/httpclient/docs/RFC6749ErrorJson.md | 160 +++++++ .../VerifiableCredentialPrimingResponse.md | 238 ++++++++++ .../docs/VerifiableCredentialProof.md | 82 ++++ .../docs/VerifiableCredentialResponse.md | 82 ++++ ...eate_verifiable_credential_request_body.go | 186 ++++++++ .../model_credential_supported_draft00.go | 226 +++++++++ .../httpclient/model_oidc_configuration.go | 74 +++ .../httpclient/model_rfc6749_error_json.go | 258 ++++++++++ ..._verifiable_credential_priming_response.go | 366 ++++++++++++++ .../model_verifiable_credential_proof.go | 150 ++++++ .../model_verifiable_credential_response.go | 150 ++++++ ...estHandlerWellKnown-hsm_enabled=false.json | 25 + ...TestHandlerWellKnown-hsm_enabled=true.json | 25 + oauth2/handler.go | 279 ++++++++++- oauth2/oauth2_auth_code_test.go | 447 +++++++++++++++--- persistence/sql/persister_nonce.go | 54 +++ persistence/sql/persister_nonce_test.go | 62 +++ spec/api.json | 191 ++++++++ spec/swagger.json | 185 ++++++++ x/fosite_storer.go | 2 + x/int_to_bytes.go | 26 + x/int_to_bytes_test.go | 52 ++ 39 files changed, 4017 insertions(+), 126 deletions(-) create mode 100644 internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md create mode 100644 internal/httpclient/docs/CredentialSupportedDraft00.md create mode 100644 internal/httpclient/docs/RFC6749ErrorJson.md create mode 100644 internal/httpclient/docs/VerifiableCredentialPrimingResponse.md create mode 100644 internal/httpclient/docs/VerifiableCredentialProof.md create mode 100644 internal/httpclient/docs/VerifiableCredentialResponse.md create mode 100644 internal/httpclient/model_create_verifiable_credential_request_body.go create mode 100644 internal/httpclient/model_credential_supported_draft00.go create mode 100644 internal/httpclient/model_rfc6749_error_json.go create mode 100644 internal/httpclient/model_verifiable_credential_priming_response.go create mode 100644 internal/httpclient/model_verifiable_credential_proof.go create mode 100644 internal/httpclient/model_verifiable_credential_response.go create mode 100644 persistence/sql/persister_nonce.go create mode 100644 persistence/sql/persister_nonce_test.go create mode 100644 x/int_to_bytes.go create mode 100644 x/int_to_bytes_test.go diff --git a/aead/xchacha20.go b/aead/xchacha20.go index cb1d2fbf27..25b0076054 100644 --- a/aead/xchacha20.go +++ b/aead/xchacha20.go @@ -9,6 +9,7 @@ import ( cryptorand "crypto/rand" "encoding/base64" "fmt" + "math" "golang.org/x/crypto/chacha20poly1305" @@ -38,6 +39,11 @@ func (x *XChaCha20Poly1305) Encrypt(ctx context.Context, plaintext, additionalDa return "", errorsx.WithStack(err) } + // Make sure the size calculation does not overflow. + if len(plaintext) > math.MaxInt-aead.NonceSize()-aead.Overhead() { + return "", errorsx.WithStack(fmt.Errorf("plaintext too large")) + } + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead()) _, err = cryptorand.Read(nonce) if err != nil { diff --git a/client/manager_test_helpers.go b/client/manager_test_helpers.go index 7eb2344964..dbfc352377 100644 --- a/client/manager_test_helpers.go +++ b/client/manager_test_helpers.go @@ -10,22 +10,19 @@ import ( "testing" "time" + "github.com/go-faker/faker/v4" "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" - - "github.com/ory/x/assertx" - "github.com/ory/x/contextx" - "github.com/ory/x/sqlcon" - - "github.com/bxcodec/faker/v3" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/fosite" - testhelpersuuid "github.com/ory/hydra/v2/internal/testhelpers/uuid" "github.com/ory/hydra/v2/x" + "github.com/ory/x/assertx" + "github.com/ory/x/contextx" + "github.com/ory/x/sqlcon" ) func TestHelperClientAutoGenerateKey(k string, m Storage) func(t *testing.T) { diff --git a/driver/config/provider.go b/driver/config/provider.go index a6149d7e5a..509ba9c9b7 100644 --- a/driver/config/provider.go +++ b/driver/config/provider.go @@ -42,6 +42,7 @@ const ( KeyOAuth2ClientRegistrationURL = "webfinger.oidc_discovery.client_registration_url" KeyOAuth2TokenURL = "webfinger.oidc_discovery.token_url" // #nosec G101 KeyOAuth2AuthURL = "webfinger.oidc_discovery.auth_url" + KeyVerifiableCredentialsURL = "webfinger.oidc_discovery.verifiable_credentials_url" // #nosec G101 KeyJWKSURL = "webfinger.oidc_discovery.jwks_url" KeyOIDCDiscoverySupportedClaims = "webfinger.oidc_discovery.supported_claims" KeyOIDCDiscoverySupportedScope = "webfinger.oidc_discovery.supported_scope" @@ -65,6 +66,7 @@ const ( KeyConsentRequestMaxAge = "ttl.login_consent_request" KeyAccessTokenLifespan = "ttl.access_token" // #nosec G101 KeyRefreshTokenLifespan = "ttl.refresh_token" // #nosec G101 + KeyVerifiableCredentialsNonceLifespan = "ttl.vc_nonce" // #nosec G101 KeyIDTokenLifespan = "ttl.id_token" // #nosec G101 KeyAuthCodeLifespan = "ttl.auth_code" KeyScopeStrategy = "strategies.scope" @@ -402,6 +404,10 @@ func (p *DefaultProvider) JWKSURL(ctx context.Context) *url.URL { return p.getProvider(ctx).RequestURIF(KeyJWKSURL, urlx.AppendPaths(p.IssuerURL(ctx), "/.well-known/jwks.json")) } +func (p *DefaultProvider) CredentialsEndpointURL(ctx context.Context) *url.URL { + return p.getProvider(ctx).RequestURIF(KeyVerifiableCredentialsURL, urlx.AppendPaths(p.PublicURL(ctx), "/credentials")) +} + type AccessTokenStrategySource interface { GetAccessTokenStrategy() AccessTokenStrategyType } diff --git a/driver/config/provider_fosite.go b/driver/config/provider_fosite.go index 053f0af10a..fa4d0a9be0 100644 --- a/driver/config/provider_fosite.go +++ b/driver/config/provider_fosite.go @@ -69,6 +69,12 @@ func (p *DefaultProvider) GetRefreshTokenLifespan(ctx context.Context) time.Dura return p.getProvider(ctx).DurationF(KeyRefreshTokenLifespan, time.Hour*720) } +var _ fosite.VerifiableCredentialsNonceLifespanProvider = (*DefaultProvider)(nil) + +func (p *DefaultProvider) GetVerifiableCredentialsNonceLifespan(ctx context.Context) time.Duration { + return p.getProvider(ctx).DurationF(KeyVerifiableCredentialsNonceLifespan, time.Hour) +} + var _ fosite.IDTokenLifespanProvider = (*DefaultProvider)(nil) func (p *DefaultProvider) GetIDTokenLifespan(ctx context.Context) time.Duration { diff --git a/driver/registry_base.go b/driver/registry_base.go index 24a58e7b84..910084ced5 100644 --- a/driver/registry_base.go +++ b/driver/registry_base.go @@ -421,7 +421,7 @@ func (m *RegistryBase) OAuth2ProviderConfig() fosite.Configurator { Config: conf, } - conf.LoadDefaultHanlders(&compose.CommonStrategy{ + conf.LoadDefaultHandlers(&compose.CommonStrategy{ CoreStrategy: fositex.NewTokenStrategy(m.Config(), hmacAtStrategy, &foauth2.DefaultJWTStrategy{ Signer: jwtAtStrategy, HMACSHAStrategy: hmacAtStrategy, diff --git a/flow/flow_test.go b/flow/flow_test.go index 7876e9a1a6..6358c47595 100644 --- a/flow/flow_test.go +++ b/flow/flow_test.go @@ -7,12 +7,11 @@ import ( "testing" "time" + "github.com/go-faker/faker/v4" "github.com/mohae/deepcopy" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/bxcodec/faker/v3" - "github.com/ory/x/sqlxx" ) diff --git a/fositex/config.go b/fositex/config.go index cc6b7fd686..19e9511055 100644 --- a/fositex/config.go +++ b/fositex/config.go @@ -58,6 +58,7 @@ var defaultFactories = []factory{ compose.OAuth2TokenIntrospectionFactory, compose.OAuth2PKCEFactory, compose.RFC7523AssertionGrantFactory, + compose.OIDCUserinfoVerifiableCredentialFactory, } func NewConfig(deps configDependencies) *Config { @@ -68,7 +69,7 @@ func NewConfig(deps configDependencies) *Config { return c } -func (c *Config) LoadDefaultHanlders(strategy interface{}) { +func (c *Config) LoadDefaultHandlers(strategy interface{}) { for _, factory := range defaultFactories { res := factory(c, c.deps.Persister(), strategy) if ah, ok := res.(fosite.AuthorizeEndpointHandler); ok { diff --git a/go.mod b/go.mod index 5e6d3fb1f9..77f8ab24f4 100644 --- a/go.mod +++ b/go.mod @@ -6,24 +6,28 @@ replace ( github.com/bradleyjkemp/cupaloy/v2 => github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.0.0 github.com/gobuffalo/packr => github.com/gobuffalo/packr v1.30.1 - github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.13 github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 + github.com/satori/go.uuid => github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b ) replace github.com/ory/hydra-client-go/v2 => ./internal/httpclient +// TODO(hperl): remove! +replace github.com/ory/fosite => github.com/ory/fosite v0.44.1-0.20230724105914-bc7e3385d777 + require ( github.com/ThalesIgnite/crypto11 v1.2.4 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 - github.com/bxcodec/faker/v3 v3.7.0 github.com/cenkalti/backoff/v3 v3.2.2 github.com/fatih/structs v1.1.0 + github.com/go-faker/faker/v4 v4.1.1 github.com/go-jose/go-jose/v3 v3.0.0 github.com/go-swagger/go-swagger v0.30.3 github.com/gobuffalo/pop/v6 v6.1.2-0.20230318123913-c85387acc9a0 github.com/gobwas/glob v0.2.3 github.com/gofrs/uuid v4.3.1+incompatible + github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/gorilla/securecookie v1.1.1 @@ -65,9 +69,9 @@ require ( go.opentelemetry.io/otel/sdk v1.11.1 go.opentelemetry.io/otel/trace v1.11.1 go.uber.org/automaxprocs v1.3.0 - golang.org/x/crypto v0.10.0 + golang.org/x/crypto v0.11.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/oauth2 v0.9.0 + golang.org/x/oauth2 v0.10.0 golang.org/x/sync v0.3.0 golang.org/x/tools v0.10.0 ) @@ -229,16 +233,18 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 // indirect go.opentelemetry.io/otel/exporters/zipkin v1.11.1 // indirect go.opentelemetry.io/otel/metric v0.33.0 // indirect - go.opentelemetry.io/proto/otlp v0.18.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/mod v0.11.0 // indirect - golang.org/x/net v0.11.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index e8f6c2baca..6321f084bd 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bxcodec/faker/v3 v3.7.0 h1:qWAFFwcyVS0ukF0UoJju1wBLO0cuPQ7JdVBPggM8kNo= -github.com/bxcodec/faker/v3 v3.7.0/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= @@ -179,6 +177,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faker/faker/v4 v4.1.1 h1:zkxj/JH/aezB4R6cTEMKU7qcVScGhlB3qRtF3D7K+rI= +github.com/go-faker/faker/v4 v4.1.1/go.mod h1:uuNc0PSRxF8nMgjGrrrU4Nw5cF30Jc6Kd0/FUTTYbhg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -314,8 +314,11 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= @@ -646,8 +649,8 @@ github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBp github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= -github.com/ory/fosite v0.44.1-0.20230704083823-8098e48b2e09 h1:2G7vOPmf0u86x6PdlVvjyFZ7bPIUruVmD5CkI++8Dlc= -github.com/ory/fosite v0.44.1-0.20230704083823-8098e48b2e09/go.mod h1:LtSYk00Kv/5McGtxntF8k8i83cxHuSM+AYlH/935PQ8= +github.com/ory/fosite v0.44.1-0.20230724105914-bc7e3385d777 h1:Jr4rVAvzQEwpkMh2hg+WPBuHZbkeXowGKodszGZt3Qk= +github.com/ory/fosite v0.44.1-0.20230724105914-bc7e3385d777/go.mod h1:ccEulu1ASipFWtzqVUOaIBgvg9HJhfKwcCUOzJAcrtw= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8= @@ -718,7 +721,7 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sawadashota/encrypta v0.0.2 h1:R46/RxYmYdxI3VOt63B637OVBHzu+fazPyLo5CqK6QE= github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1:0b8DF5kR0PhRoRXDiEEdzrgBc8UqVY4JWLkQJCRsLME= @@ -878,8 +881,8 @@ go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOl go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= -go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -916,8 +919,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1004,8 +1007,8 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1019,8 +1022,8 @@ golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= -golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1113,8 +1116,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1132,8 +1135,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1276,8 +1279,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1314,8 +1321,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index c83b13fa73..8fd9b40623 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -14,6 +14,8 @@ docs/AcceptOAuth2ConsentRequest.md docs/AcceptOAuth2ConsentRequestSession.md docs/AcceptOAuth2LoginRequest.md docs/CreateJsonWebKeySet.md +docs/CreateVerifiableCredentialRequestBody.md +docs/CredentialSupportedDraft00.md docs/ErrorOAuth2.md docs/GenericError.md docs/GetVersion200Response.md @@ -43,6 +45,7 @@ docs/OidcConfiguration.md docs/OidcUserInfo.md docs/Pagination.md docs/PaginationHeaders.md +docs/RFC6749ErrorJson.md docs/RejectOAuth2Request.md docs/TokenPagination.md docs/TokenPaginationHeaders.md @@ -51,6 +54,9 @@ docs/TokenPaginationResponseHeaders.md docs/TrustOAuth2JwtGrantIssuer.md docs/TrustedOAuth2JwtGrantIssuer.md docs/TrustedOAuth2JwtGrantJsonWebKey.md +docs/VerifiableCredentialPrimingResponse.md +docs/VerifiableCredentialProof.md +docs/VerifiableCredentialResponse.md docs/Version.md docs/WellknownApi.md git_push.sh @@ -60,6 +66,8 @@ model_accept_o_auth2_consent_request.go model_accept_o_auth2_consent_request_session.go model_accept_o_auth2_login_request.go model_create_json_web_key_set.go +model_create_verifiable_credential_request_body.go +model_credential_supported_draft00.go model_error_o_auth2.go model_generic_error.go model_get_version_200_response.go @@ -86,6 +94,7 @@ model_oidc_user_info.go model_pagination.go model_pagination_headers.go model_reject_o_auth2_request.go +model_rfc6749_error_json.go model_token_pagination.go model_token_pagination_headers.go model_token_pagination_request_parameters.go @@ -93,6 +102,9 @@ model_token_pagination_response_headers.go model_trust_o_auth2_jwt_grant_issuer.go model_trusted_o_auth2_jwt_grant_issuer.go model_trusted_o_auth2_jwt_grant_json_web_key.go +model_verifiable_credential_priming_response.go +model_verifiable_credential_proof.go +model_verifiable_credential_response.go model_version.go response.go utils.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index f72f589f45..54e38678e6 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -118,6 +118,7 @@ Class | Method | HTTP request | Description *OAuth2Api* | [**SetOAuth2ClientLifespans**](docs/OAuth2Api.md#setoauth2clientlifespans) | **Put** /admin/clients/{id}/lifespans | Set OAuth2 Client Token Lifespans *OAuth2Api* | [**TrustOAuth2JwtGrantIssuer**](docs/OAuth2Api.md#trustoauth2jwtgrantissuer) | **Post** /admin/trust/grants/jwt-bearer/issuers | Trust OAuth2 JWT Bearer Grant Type Issuer *OidcApi* | [**CreateOidcDynamicClient**](docs/OidcApi.md#createoidcdynamicclient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration +*OidcApi* | [**CreateVerifiableCredential**](docs/OidcApi.md#createverifiablecredential) | **Post** /credentials | Issues a Verifiable Credential *OidcApi* | [**DeleteOidcDynamicClient**](docs/OidcApi.md#deleteoidcdynamicclient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol *OidcApi* | [**DiscoverOidcConfiguration**](docs/OidcApi.md#discoveroidcconfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery *OidcApi* | [**GetOidcDynamicClient**](docs/OidcApi.md#getoidcdynamicclient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration @@ -133,6 +134,8 @@ Class | Method | HTTP request | Description - [AcceptOAuth2ConsentRequestSession](docs/AcceptOAuth2ConsentRequestSession.md) - [AcceptOAuth2LoginRequest](docs/AcceptOAuth2LoginRequest.md) - [CreateJsonWebKeySet](docs/CreateJsonWebKeySet.md) + - [CreateVerifiableCredentialRequestBody](docs/CreateVerifiableCredentialRequestBody.md) + - [CredentialSupportedDraft00](docs/CredentialSupportedDraft00.md) - [ErrorOAuth2](docs/ErrorOAuth2.md) - [GenericError](docs/GenericError.md) - [GetVersion200Response](docs/GetVersion200Response.md) @@ -158,6 +161,7 @@ Class | Method | HTTP request | Description - [OidcUserInfo](docs/OidcUserInfo.md) - [Pagination](docs/Pagination.md) - [PaginationHeaders](docs/PaginationHeaders.md) + - [RFC6749ErrorJson](docs/RFC6749ErrorJson.md) - [RejectOAuth2Request](docs/RejectOAuth2Request.md) - [TokenPagination](docs/TokenPagination.md) - [TokenPaginationHeaders](docs/TokenPaginationHeaders.md) @@ -166,6 +170,9 @@ Class | Method | HTTP request | Description - [TrustOAuth2JwtGrantIssuer](docs/TrustOAuth2JwtGrantIssuer.md) - [TrustedOAuth2JwtGrantIssuer](docs/TrustedOAuth2JwtGrantIssuer.md) - [TrustedOAuth2JwtGrantJsonWebKey](docs/TrustedOAuth2JwtGrantJsonWebKey.md) + - [VerifiableCredentialPrimingResponse](docs/VerifiableCredentialPrimingResponse.md) + - [VerifiableCredentialProof](docs/VerifiableCredentialProof.md) + - [VerifiableCredentialResponse](docs/VerifiableCredentialResponse.md) - [Version](docs/Version.md) diff --git a/internal/httpclient/api/openapi.yaml b/internal/httpclient/api/openapi.yaml index f7c19f50c4..0841ffa5e9 100644 --- a/internal/httpclient/api/openapi.yaml +++ b/internal/httpclient/api/openapi.yaml @@ -1365,6 +1365,44 @@ paths: summary: Get Trusted OAuth2 JWT Bearer Grant Type Issuer tags: - oAuth2 + /credentials: + post: + description: |- + This endpoint creates a verifiable credential that attests that the user + authenticated with the provided access token owns a certain public/private key + pair. + + More information can be found at + https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. + operationId: createVerifiableCredential + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateVerifiableCredentialRequestBody' + x-originalParamName: Body + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/verifiableCredentialResponse' + description: verifiableCredentialResponse + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/verifiableCredentialPrimingResponse' + description: verifiableCredentialPrimingResponse + default: + content: + application/json: + schema: + $ref: '#/components/schemas/errorOAuth2' + description: errorOAuth2 + summary: Issues a Verifiable Credential + tags: + - oidc /health/alive: get: description: "This endpoint returns a HTTP 200 status code when Ory Hydra is\ @@ -1771,6 +1809,27 @@ components: type: array description: Paginated OAuth2 Client List Response schemas: + CreateVerifiableCredentialRequestBody: + example: + types: + - types + - types + format: format + proof: + proof_type: proof_type + jwt: jwt + properties: + format: + type: string + proof: + $ref: '#/components/schemas/VerifiableCredentialProof' + types: + items: + type: string + type: array + title: CreateVerifiableCredentialRequestBody contains the request body to request + a verifiable credential. + type: object DefaultError: {} JSONRawMessage: title: "JSONRawMessage represents a json.RawMessage that works well with JSON,\ @@ -1797,6 +1856,21 @@ components: format: uuid4 nullable: true type: string + RFC6749ErrorJson: + properties: + error: + type: string + error_debug: + type: string + error_description: + type: string + error_hint: + type: string + status_code: + format: int64 + type: integer + title: RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error. + type: object StringSliceJSONFormat: items: type: string @@ -1809,6 +1883,17 @@ components: UUID: format: uuid4 type: string + VerifiableCredentialProof: + example: + proof_type: proof_type + jwt: jwt + properties: + jwt: + type: string + proof_type: + type: string + title: VerifiableCredentialProof contains the proof of a verifiable credential. + type: object acceptOAuth2ConsentRequest: properties: grant_access_token_audience: @@ -1950,6 +2035,52 @@ components: - kid - use type: object + credentialSupportedDraft00: + description: Includes information about the supported verifiable credentials. + example: + types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format + properties: + cryptographic_binding_methods_supported: + description: |- + OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported + + Contains a list of cryptographic binding methods supported for signing the proof. + items: + type: string + type: array + cryptographic_suites_supported: + description: |- + OpenID Connect Verifiable Credentials Cryptographic Suites Supported + + Contains a list of cryptographic suites methods supported for signing the proof. + items: + type: string + type: array + format: + description: |- + OpenID Connect Verifiable Credentials Format + + Contains the format that is supported by this authorization server. + type: string + types: + description: |- + OpenID Connect Verifiable Credentials Types + + Contains the types of verifiable credentials supported. + items: + type: string + type: array + title: Verifiable Credentials Metadata (Draft 00) + type: object errorOAuth2: description: Error example: @@ -3527,8 +3658,30 @@ components: code_challenge_methods_supported: - code_challenge_methods_supported - code_challenge_methods_supported + credentials_endpoint_draft_00: credentials_endpoint_draft_00 frontchannel_logout_session_supported: true jwks_uri: "https://{slug}.projects.oryapis.com/.well-known/jwks.json" + credentials_supported_draft_00: + - types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format + - types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format subject_types_supported: - subject_types_supported - subject_types_supported @@ -3575,6 +3728,20 @@ components: items: type: string type: array + credentials_endpoint_draft_00: + description: |- + OpenID Connect Verifiable Credentials Endpoint + + Contains the URL of the Verifiable Credentials Endpoint. + type: string + credentials_supported_draft_00: + description: |- + OpenID Connect Verifiable Credentials Supported + + JSON array containing a list of the Verifiable Credentials supported by this authorization server. + items: + $ref: '#/components/schemas/credentialSupportedDraft00' + type: array end_session_endpoint: description: |- OpenID Connect End-Session Endpoint @@ -4147,6 +4314,40 @@ components: type: object unexpectedError: type: string + verifiableCredentialPrimingResponse: + properties: + c_nonce: + type: string + c_nonce_expires_in: + format: int64 + type: integer + error: + type: string + error_debug: + type: string + error_description: + type: string + error_hint: + type: string + format: + type: string + status_code: + format: int64 + type: integer + title: VerifiableCredentialPrimingResponse contains the nonce to include in + the proof-of-possession JWT. + type: object + verifiableCredentialResponse: + example: + credential_draft_00: credential_draft_00 + format: format + properties: + credential_draft_00: + type: string + format: + type: string + title: VerifiableCredentialResponse contains the verifiable credential. + type: object version: properties: version: diff --git a/internal/httpclient/api_oidc.go b/internal/httpclient/api_oidc.go index 285774a253..814348a137 100644 --- a/internal/httpclient/api_oidc.go +++ b/internal/httpclient/api_oidc.go @@ -162,6 +162,136 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl return localVarReturnValue, localVarHTTPResponse, nil } +type ApiCreateVerifiableCredentialRequest struct { + ctx context.Context + ApiService *OidcApiService + createVerifiableCredentialRequestBody *CreateVerifiableCredentialRequestBody +} + +func (r ApiCreateVerifiableCredentialRequest) CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody CreateVerifiableCredentialRequestBody) ApiCreateVerifiableCredentialRequest { + r.createVerifiableCredentialRequestBody = &createVerifiableCredentialRequestBody + return r +} + +func (r ApiCreateVerifiableCredentialRequest) Execute() (*VerifiableCredentialResponse, *http.Response, error) { + return r.ApiService.CreateVerifiableCredentialExecute(r) +} + +/* +CreateVerifiableCredential Issues a Verifiable Credential + +This endpoint creates a verifiable credential that attests that the user +authenticated with the provided access token owns a certain public/private key +pair. + +More information can be found at +https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiCreateVerifiableCredentialRequest +*/ +func (a *OidcApiService) CreateVerifiableCredential(ctx context.Context) ApiCreateVerifiableCredentialRequest { + return ApiCreateVerifiableCredentialRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return VerifiableCredentialResponse +func (a *OidcApiService) CreateVerifiableCredentialExecute(r ApiCreateVerifiableCredentialRequest) (*VerifiableCredentialResponse, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *VerifiableCredentialResponse + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.CreateVerifiableCredential") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/credentials" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.createVerifiableCredentialRequestBody + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v VerifiableCredentialPrimingResponse + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + var v ErrorOAuth2 + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + type ApiDeleteOidcDynamicClientRequest struct { ctx context.Context ApiService *OidcApiService diff --git a/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md b/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md new file mode 100644 index 0000000000..24a2834e86 --- /dev/null +++ b/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md @@ -0,0 +1,108 @@ +# CreateVerifiableCredentialRequestBody + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Format** | Pointer to **string** | | [optional] +**Proof** | Pointer to [**VerifiableCredentialProof**](VerifiableCredentialProof.md) | | [optional] +**Types** | Pointer to **[]string** | | [optional] + +## Methods + +### NewCreateVerifiableCredentialRequestBody + +`func NewCreateVerifiableCredentialRequestBody() *CreateVerifiableCredentialRequestBody` + +NewCreateVerifiableCredentialRequestBody instantiates a new CreateVerifiableCredentialRequestBody object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateVerifiableCredentialRequestBodyWithDefaults + +`func NewCreateVerifiableCredentialRequestBodyWithDefaults() *CreateVerifiableCredentialRequestBody` + +NewCreateVerifiableCredentialRequestBodyWithDefaults instantiates a new CreateVerifiableCredentialRequestBody object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetFormat + +`func (o *CreateVerifiableCredentialRequestBody) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *CreateVerifiableCredentialRequestBody) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *CreateVerifiableCredentialRequestBody) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *CreateVerifiableCredentialRequestBody) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetProof + +`func (o *CreateVerifiableCredentialRequestBody) GetProof() VerifiableCredentialProof` + +GetProof returns the Proof field if non-nil, zero value otherwise. + +### GetProofOk + +`func (o *CreateVerifiableCredentialRequestBody) GetProofOk() (*VerifiableCredentialProof, bool)` + +GetProofOk returns a tuple with the Proof field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProof + +`func (o *CreateVerifiableCredentialRequestBody) SetProof(v VerifiableCredentialProof)` + +SetProof sets Proof field to given value. + +### HasProof + +`func (o *CreateVerifiableCredentialRequestBody) HasProof() bool` + +HasProof returns a boolean if a field has been set. + +### GetTypes + +`func (o *CreateVerifiableCredentialRequestBody) GetTypes() []string` + +GetTypes returns the Types field if non-nil, zero value otherwise. + +### GetTypesOk + +`func (o *CreateVerifiableCredentialRequestBody) GetTypesOk() (*[]string, bool)` + +GetTypesOk returns a tuple with the Types field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTypes + +`func (o *CreateVerifiableCredentialRequestBody) SetTypes(v []string)` + +SetTypes sets Types field to given value. + +### HasTypes + +`func (o *CreateVerifiableCredentialRequestBody) HasTypes() bool` + +HasTypes returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/CredentialSupportedDraft00.md b/internal/httpclient/docs/CredentialSupportedDraft00.md new file mode 100644 index 0000000000..1738f518fa --- /dev/null +++ b/internal/httpclient/docs/CredentialSupportedDraft00.md @@ -0,0 +1,134 @@ +# CredentialSupportedDraft00 + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CryptographicBindingMethodsSupported** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported Contains a list of cryptographic binding methods supported for signing the proof. | [optional] +**CryptographicSuitesSupported** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Cryptographic Suites Supported Contains a list of cryptographic suites methods supported for signing the proof. | [optional] +**Format** | Pointer to **string** | OpenID Connect Verifiable Credentials Format Contains the format that is supported by this authorization server. | [optional] +**Types** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Types Contains the types of verifiable credentials supported. | [optional] + +## Methods + +### NewCredentialSupportedDraft00 + +`func NewCredentialSupportedDraft00() *CredentialSupportedDraft00` + +NewCredentialSupportedDraft00 instantiates a new CredentialSupportedDraft00 object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCredentialSupportedDraft00WithDefaults + +`func NewCredentialSupportedDraft00WithDefaults() *CredentialSupportedDraft00` + +NewCredentialSupportedDraft00WithDefaults instantiates a new CredentialSupportedDraft00 object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupported() []string` + +GetCryptographicBindingMethodsSupported returns the CryptographicBindingMethodsSupported field if non-nil, zero value otherwise. + +### GetCryptographicBindingMethodsSupportedOk + +`func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupportedOk() (*[]string, bool)` + +GetCryptographicBindingMethodsSupportedOk returns a tuple with the CryptographicBindingMethodsSupported field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) SetCryptographicBindingMethodsSupported(v []string)` + +SetCryptographicBindingMethodsSupported sets CryptographicBindingMethodsSupported field to given value. + +### HasCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) HasCryptographicBindingMethodsSupported() bool` + +HasCryptographicBindingMethodsSupported returns a boolean if a field has been set. + +### GetCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupported() []string` + +GetCryptographicSuitesSupported returns the CryptographicSuitesSupported field if non-nil, zero value otherwise. + +### GetCryptographicSuitesSupportedOk + +`func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupportedOk() (*[]string, bool)` + +GetCryptographicSuitesSupportedOk returns a tuple with the CryptographicSuitesSupported field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) SetCryptographicSuitesSupported(v []string)` + +SetCryptographicSuitesSupported sets CryptographicSuitesSupported field to given value. + +### HasCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) HasCryptographicSuitesSupported() bool` + +HasCryptographicSuitesSupported returns a boolean if a field has been set. + +### GetFormat + +`func (o *CredentialSupportedDraft00) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *CredentialSupportedDraft00) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *CredentialSupportedDraft00) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *CredentialSupportedDraft00) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetTypes + +`func (o *CredentialSupportedDraft00) GetTypes() []string` + +GetTypes returns the Types field if non-nil, zero value otherwise. + +### GetTypesOk + +`func (o *CredentialSupportedDraft00) GetTypesOk() (*[]string, bool)` + +GetTypesOk returns a tuple with the Types field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTypes + +`func (o *CredentialSupportedDraft00) SetTypes(v []string)` + +SetTypes sets Types field to given value. + +### HasTypes + +`func (o *CredentialSupportedDraft00) HasTypes() bool` + +HasTypes returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/OidcApi.md b/internal/httpclient/docs/OidcApi.md index 8087d0565d..e1884fa2ad 100644 --- a/internal/httpclient/docs/OidcApi.md +++ b/internal/httpclient/docs/OidcApi.md @@ -5,6 +5,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- [**CreateOidcDynamicClient**](OidcApi.md#CreateOidcDynamicClient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration +[**CreateVerifiableCredential**](OidcApi.md#CreateVerifiableCredential) | **Post** /credentials | Issues a Verifiable Credential [**DeleteOidcDynamicClient**](OidcApi.md#DeleteOidcDynamicClient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol [**DiscoverOidcConfiguration**](OidcApi.md#DiscoverOidcConfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery [**GetOidcDynamicClient**](OidcApi.md#GetOidcDynamicClient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration @@ -80,6 +81,72 @@ No authorization required [[Back to README]](../README.md) +## CreateVerifiableCredential + +> VerifiableCredentialResponse CreateVerifiableCredential(ctx).CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody).Execute() + +Issues a Verifiable Credential + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "./openapi" +) + +func main() { + createVerifiableCredentialRequestBody := *openapiclient.NewCreateVerifiableCredentialRequestBody() // CreateVerifiableCredentialRequestBody | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcApi.CreateVerifiableCredential(context.Background()).CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.CreateVerifiableCredential``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateVerifiableCredential`: VerifiableCredentialResponse + fmt.Fprintf(os.Stdout, "Response from `OidcApi.CreateVerifiableCredential`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateVerifiableCredentialRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **createVerifiableCredentialRequestBody** | [**CreateVerifiableCredentialRequestBody**](CreateVerifiableCredentialRequestBody.md) | | + +### Return type + +[**VerifiableCredentialResponse**](VerifiableCredentialResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## DeleteOidcDynamicClient > DeleteOidcDynamicClient(ctx, id).Execute() diff --git a/internal/httpclient/docs/OidcConfiguration.md b/internal/httpclient/docs/OidcConfiguration.md index 723bd6a8b4..1b20c7d873 100644 --- a/internal/httpclient/docs/OidcConfiguration.md +++ b/internal/httpclient/docs/OidcConfiguration.md @@ -10,6 +10,8 @@ Name | Type | Description | Notes **ClaimsParameterSupported** | Pointer to **bool** | OpenID Connect Claims Parameter Parameter Supported Boolean value specifying whether the OP supports use of the claims parameter, with true indicating support. | [optional] **ClaimsSupported** | Pointer to **[]string** | OpenID Connect Supported Claims JSON array containing a list of the Claim Names of the Claims that the OpenID Provider MAY be able to supply values for. Note that for privacy or other reasons, this might not be an exhaustive list. | [optional] **CodeChallengeMethodsSupported** | Pointer to **[]string** | OAuth 2.0 PKCE Supported Code Challenge Methods JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported by this authorization server. | [optional] +**CredentialsEndpointDraft00** | Pointer to **string** | OpenID Connect Verifiable Credentials Endpoint Contains the URL of the Verifiable Credentials Endpoint. | [optional] +**CredentialsSupportedDraft00** | Pointer to [**[]CredentialSupportedDraft00**](CredentialSupportedDraft00.md) | OpenID Connect Verifiable Credentials Supported JSON array containing a list of the Verifiable Credentials supported by this authorization server. | [optional] **EndSessionEndpoint** | Pointer to **string** | OpenID Connect End-Session Endpoint URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP. | [optional] **FrontchannelLogoutSessionSupported** | Pointer to **bool** | OpenID Connect Front-Channel Logout Session Required Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to identify the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also included in ID Tokens issued by the OP. | [optional] **FrontchannelLogoutSupported** | Pointer to **bool** | OpenID Connect Front-Channel Logout Supported Boolean value specifying whether the OP supports HTTP-based logout, with true indicating support. | [optional] @@ -198,6 +200,56 @@ SetCodeChallengeMethodsSupported sets CodeChallengeMethodsSupported field to giv HasCodeChallengeMethodsSupported returns a boolean if a field has been set. +### GetCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) GetCredentialsEndpointDraft00() string` + +GetCredentialsEndpointDraft00 returns the CredentialsEndpointDraft00 field if non-nil, zero value otherwise. + +### GetCredentialsEndpointDraft00Ok + +`func (o *OidcConfiguration) GetCredentialsEndpointDraft00Ok() (*string, bool)` + +GetCredentialsEndpointDraft00Ok returns a tuple with the CredentialsEndpointDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) SetCredentialsEndpointDraft00(v string)` + +SetCredentialsEndpointDraft00 sets CredentialsEndpointDraft00 field to given value. + +### HasCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) HasCredentialsEndpointDraft00() bool` + +HasCredentialsEndpointDraft00 returns a boolean if a field has been set. + +### GetCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) GetCredentialsSupportedDraft00() []CredentialSupportedDraft00` + +GetCredentialsSupportedDraft00 returns the CredentialsSupportedDraft00 field if non-nil, zero value otherwise. + +### GetCredentialsSupportedDraft00Ok + +`func (o *OidcConfiguration) GetCredentialsSupportedDraft00Ok() (*[]CredentialSupportedDraft00, bool)` + +GetCredentialsSupportedDraft00Ok returns a tuple with the CredentialsSupportedDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) SetCredentialsSupportedDraft00(v []CredentialSupportedDraft00)` + +SetCredentialsSupportedDraft00 sets CredentialsSupportedDraft00 field to given value. + +### HasCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) HasCredentialsSupportedDraft00() bool` + +HasCredentialsSupportedDraft00 returns a boolean if a field has been set. + ### GetEndSessionEndpoint `func (o *OidcConfiguration) GetEndSessionEndpoint() string` diff --git a/internal/httpclient/docs/RFC6749ErrorJson.md b/internal/httpclient/docs/RFC6749ErrorJson.md new file mode 100644 index 0000000000..570e38c5a9 --- /dev/null +++ b/internal/httpclient/docs/RFC6749ErrorJson.md @@ -0,0 +1,160 @@ +# RFC6749ErrorJson + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Error** | Pointer to **string** | | [optional] +**ErrorDebug** | Pointer to **string** | | [optional] +**ErrorDescription** | Pointer to **string** | | [optional] +**ErrorHint** | Pointer to **string** | | [optional] +**StatusCode** | Pointer to **int64** | | [optional] + +## Methods + +### NewRFC6749ErrorJson + +`func NewRFC6749ErrorJson() *RFC6749ErrorJson` + +NewRFC6749ErrorJson instantiates a new RFC6749ErrorJson object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewRFC6749ErrorJsonWithDefaults + +`func NewRFC6749ErrorJsonWithDefaults() *RFC6749ErrorJson` + +NewRFC6749ErrorJsonWithDefaults instantiates a new RFC6749ErrorJson object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetError + +`func (o *RFC6749ErrorJson) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *RFC6749ErrorJson) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *RFC6749ErrorJson) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *RFC6749ErrorJson) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetErrorDebug + +`func (o *RFC6749ErrorJson) GetErrorDebug() string` + +GetErrorDebug returns the ErrorDebug field if non-nil, zero value otherwise. + +### GetErrorDebugOk + +`func (o *RFC6749ErrorJson) GetErrorDebugOk() (*string, bool)` + +GetErrorDebugOk returns a tuple with the ErrorDebug field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDebug + +`func (o *RFC6749ErrorJson) SetErrorDebug(v string)` + +SetErrorDebug sets ErrorDebug field to given value. + +### HasErrorDebug + +`func (o *RFC6749ErrorJson) HasErrorDebug() bool` + +HasErrorDebug returns a boolean if a field has been set. + +### GetErrorDescription + +`func (o *RFC6749ErrorJson) GetErrorDescription() string` + +GetErrorDescription returns the ErrorDescription field if non-nil, zero value otherwise. + +### GetErrorDescriptionOk + +`func (o *RFC6749ErrorJson) GetErrorDescriptionOk() (*string, bool)` + +GetErrorDescriptionOk returns a tuple with the ErrorDescription field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDescription + +`func (o *RFC6749ErrorJson) SetErrorDescription(v string)` + +SetErrorDescription sets ErrorDescription field to given value. + +### HasErrorDescription + +`func (o *RFC6749ErrorJson) HasErrorDescription() bool` + +HasErrorDescription returns a boolean if a field has been set. + +### GetErrorHint + +`func (o *RFC6749ErrorJson) GetErrorHint() string` + +GetErrorHint returns the ErrorHint field if non-nil, zero value otherwise. + +### GetErrorHintOk + +`func (o *RFC6749ErrorJson) GetErrorHintOk() (*string, bool)` + +GetErrorHintOk returns a tuple with the ErrorHint field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorHint + +`func (o *RFC6749ErrorJson) SetErrorHint(v string)` + +SetErrorHint sets ErrorHint field to given value. + +### HasErrorHint + +`func (o *RFC6749ErrorJson) HasErrorHint() bool` + +HasErrorHint returns a boolean if a field has been set. + +### GetStatusCode + +`func (o *RFC6749ErrorJson) GetStatusCode() int64` + +GetStatusCode returns the StatusCode field if non-nil, zero value otherwise. + +### GetStatusCodeOk + +`func (o *RFC6749ErrorJson) GetStatusCodeOk() (*int64, bool)` + +GetStatusCodeOk returns a tuple with the StatusCode field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatusCode + +`func (o *RFC6749ErrorJson) SetStatusCode(v int64)` + +SetStatusCode sets StatusCode field to given value. + +### HasStatusCode + +`func (o *RFC6749ErrorJson) HasStatusCode() bool` + +HasStatusCode returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md b/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md new file mode 100644 index 0000000000..5668ebf5a0 --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md @@ -0,0 +1,238 @@ +# VerifiableCredentialPrimingResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CNonce** | Pointer to **string** | | [optional] +**CNonceExpiresIn** | Pointer to **int64** | | [optional] +**Error** | Pointer to **string** | | [optional] +**ErrorDebug** | Pointer to **string** | | [optional] +**ErrorDescription** | Pointer to **string** | | [optional] +**ErrorHint** | Pointer to **string** | | [optional] +**Format** | Pointer to **string** | | [optional] +**StatusCode** | Pointer to **int64** | | [optional] + +## Methods + +### NewVerifiableCredentialPrimingResponse + +`func NewVerifiableCredentialPrimingResponse() *VerifiableCredentialPrimingResponse` + +NewVerifiableCredentialPrimingResponse instantiates a new VerifiableCredentialPrimingResponse object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialPrimingResponseWithDefaults + +`func NewVerifiableCredentialPrimingResponseWithDefaults() *VerifiableCredentialPrimingResponse` + +NewVerifiableCredentialPrimingResponseWithDefaults instantiates a new VerifiableCredentialPrimingResponse object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCNonce + +`func (o *VerifiableCredentialPrimingResponse) GetCNonce() string` + +GetCNonce returns the CNonce field if non-nil, zero value otherwise. + +### GetCNonceOk + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceOk() (*string, bool)` + +GetCNonceOk returns a tuple with the CNonce field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCNonce + +`func (o *VerifiableCredentialPrimingResponse) SetCNonce(v string)` + +SetCNonce sets CNonce field to given value. + +### HasCNonce + +`func (o *VerifiableCredentialPrimingResponse) HasCNonce() bool` + +HasCNonce returns a boolean if a field has been set. + +### GetCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresIn() int64` + +GetCNonceExpiresIn returns the CNonceExpiresIn field if non-nil, zero value otherwise. + +### GetCNonceExpiresInOk + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresInOk() (*int64, bool)` + +GetCNonceExpiresInOk returns a tuple with the CNonceExpiresIn field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) SetCNonceExpiresIn(v int64)` + +SetCNonceExpiresIn sets CNonceExpiresIn field to given value. + +### HasCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) HasCNonceExpiresIn() bool` + +HasCNonceExpiresIn returns a boolean if a field has been set. + +### GetError + +`func (o *VerifiableCredentialPrimingResponse) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *VerifiableCredentialPrimingResponse) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *VerifiableCredentialPrimingResponse) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDebug() string` + +GetErrorDebug returns the ErrorDebug field if non-nil, zero value otherwise. + +### GetErrorDebugOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDebugOk() (*string, bool)` + +GetErrorDebugOk returns a tuple with the ErrorDebug field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) SetErrorDebug(v string)` + +SetErrorDebug sets ErrorDebug field to given value. + +### HasErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) HasErrorDebug() bool` + +HasErrorDebug returns a boolean if a field has been set. + +### GetErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDescription() string` + +GetErrorDescription returns the ErrorDescription field if non-nil, zero value otherwise. + +### GetErrorDescriptionOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDescriptionOk() (*string, bool)` + +GetErrorDescriptionOk returns a tuple with the ErrorDescription field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) SetErrorDescription(v string)` + +SetErrorDescription sets ErrorDescription field to given value. + +### HasErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) HasErrorDescription() bool` + +HasErrorDescription returns a boolean if a field has been set. + +### GetErrorHint + +`func (o *VerifiableCredentialPrimingResponse) GetErrorHint() string` + +GetErrorHint returns the ErrorHint field if non-nil, zero value otherwise. + +### GetErrorHintOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorHintOk() (*string, bool)` + +GetErrorHintOk returns a tuple with the ErrorHint field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorHint + +`func (o *VerifiableCredentialPrimingResponse) SetErrorHint(v string)` + +SetErrorHint sets ErrorHint field to given value. + +### HasErrorHint + +`func (o *VerifiableCredentialPrimingResponse) HasErrorHint() bool` + +HasErrorHint returns a boolean if a field has been set. + +### GetFormat + +`func (o *VerifiableCredentialPrimingResponse) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *VerifiableCredentialPrimingResponse) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *VerifiableCredentialPrimingResponse) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *VerifiableCredentialPrimingResponse) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetStatusCode + +`func (o *VerifiableCredentialPrimingResponse) GetStatusCode() int64` + +GetStatusCode returns the StatusCode field if non-nil, zero value otherwise. + +### GetStatusCodeOk + +`func (o *VerifiableCredentialPrimingResponse) GetStatusCodeOk() (*int64, bool)` + +GetStatusCodeOk returns a tuple with the StatusCode field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatusCode + +`func (o *VerifiableCredentialPrimingResponse) SetStatusCode(v int64)` + +SetStatusCode sets StatusCode field to given value. + +### HasStatusCode + +`func (o *VerifiableCredentialPrimingResponse) HasStatusCode() bool` + +HasStatusCode returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialProof.md b/internal/httpclient/docs/VerifiableCredentialProof.md new file mode 100644 index 0000000000..9412036cbb --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialProof.md @@ -0,0 +1,82 @@ +# VerifiableCredentialProof + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Jwt** | Pointer to **string** | | [optional] +**ProofType** | Pointer to **string** | | [optional] + +## Methods + +### NewVerifiableCredentialProof + +`func NewVerifiableCredentialProof() *VerifiableCredentialProof` + +NewVerifiableCredentialProof instantiates a new VerifiableCredentialProof object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialProofWithDefaults + +`func NewVerifiableCredentialProofWithDefaults() *VerifiableCredentialProof` + +NewVerifiableCredentialProofWithDefaults instantiates a new VerifiableCredentialProof object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetJwt + +`func (o *VerifiableCredentialProof) GetJwt() string` + +GetJwt returns the Jwt field if non-nil, zero value otherwise. + +### GetJwtOk + +`func (o *VerifiableCredentialProof) GetJwtOk() (*string, bool)` + +GetJwtOk returns a tuple with the Jwt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetJwt + +`func (o *VerifiableCredentialProof) SetJwt(v string)` + +SetJwt sets Jwt field to given value. + +### HasJwt + +`func (o *VerifiableCredentialProof) HasJwt() bool` + +HasJwt returns a boolean if a field has been set. + +### GetProofType + +`func (o *VerifiableCredentialProof) GetProofType() string` + +GetProofType returns the ProofType field if non-nil, zero value otherwise. + +### GetProofTypeOk + +`func (o *VerifiableCredentialProof) GetProofTypeOk() (*string, bool)` + +GetProofTypeOk returns a tuple with the ProofType field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProofType + +`func (o *VerifiableCredentialProof) SetProofType(v string)` + +SetProofType sets ProofType field to given value. + +### HasProofType + +`func (o *VerifiableCredentialProof) HasProofType() bool` + +HasProofType returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialResponse.md b/internal/httpclient/docs/VerifiableCredentialResponse.md new file mode 100644 index 0000000000..aa594541c4 --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialResponse.md @@ -0,0 +1,82 @@ +# VerifiableCredentialResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CredentialDraft00** | Pointer to **string** | | [optional] +**Format** | Pointer to **string** | | [optional] + +## Methods + +### NewVerifiableCredentialResponse + +`func NewVerifiableCredentialResponse() *VerifiableCredentialResponse` + +NewVerifiableCredentialResponse instantiates a new VerifiableCredentialResponse object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialResponseWithDefaults + +`func NewVerifiableCredentialResponseWithDefaults() *VerifiableCredentialResponse` + +NewVerifiableCredentialResponseWithDefaults instantiates a new VerifiableCredentialResponse object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCredentialDraft00 + +`func (o *VerifiableCredentialResponse) GetCredentialDraft00() string` + +GetCredentialDraft00 returns the CredentialDraft00 field if non-nil, zero value otherwise. + +### GetCredentialDraft00Ok + +`func (o *VerifiableCredentialResponse) GetCredentialDraft00Ok() (*string, bool)` + +GetCredentialDraft00Ok returns a tuple with the CredentialDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialDraft00 + +`func (o *VerifiableCredentialResponse) SetCredentialDraft00(v string)` + +SetCredentialDraft00 sets CredentialDraft00 field to given value. + +### HasCredentialDraft00 + +`func (o *VerifiableCredentialResponse) HasCredentialDraft00() bool` + +HasCredentialDraft00 returns a boolean if a field has been set. + +### GetFormat + +`func (o *VerifiableCredentialResponse) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *VerifiableCredentialResponse) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *VerifiableCredentialResponse) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *VerifiableCredentialResponse) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/model_create_verifiable_credential_request_body.go b/internal/httpclient/model_create_verifiable_credential_request_body.go new file mode 100644 index 0000000000..290f703722 --- /dev/null +++ b/internal/httpclient/model_create_verifiable_credential_request_body.go @@ -0,0 +1,186 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// CreateVerifiableCredentialRequestBody struct for CreateVerifiableCredentialRequestBody +type CreateVerifiableCredentialRequestBody struct { + Format *string `json:"format,omitempty"` + Proof *VerifiableCredentialProof `json:"proof,omitempty"` + Types []string `json:"types,omitempty"` +} + +// NewCreateVerifiableCredentialRequestBody instantiates a new CreateVerifiableCredentialRequestBody object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateVerifiableCredentialRequestBody() *CreateVerifiableCredentialRequestBody { + this := CreateVerifiableCredentialRequestBody{} + return &this +} + +// NewCreateVerifiableCredentialRequestBodyWithDefaults instantiates a new CreateVerifiableCredentialRequestBody object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateVerifiableCredentialRequestBodyWithDefaults() *CreateVerifiableCredentialRequestBody { + this := CreateVerifiableCredentialRequestBody{} + return &this +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetFormat() string { + if o == nil || o.Format == nil { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetFormatOk() (*string, bool) { + if o == nil || o.Format == nil { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasFormat() bool { + if o != nil && o.Format != nil { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *CreateVerifiableCredentialRequestBody) SetFormat(v string) { + o.Format = &v +} + +// GetProof returns the Proof field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetProof() VerifiableCredentialProof { + if o == nil || o.Proof == nil { + var ret VerifiableCredentialProof + return ret + } + return *o.Proof +} + +// GetProofOk returns a tuple with the Proof field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetProofOk() (*VerifiableCredentialProof, bool) { + if o == nil || o.Proof == nil { + return nil, false + } + return o.Proof, true +} + +// HasProof returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasProof() bool { + if o != nil && o.Proof != nil { + return true + } + + return false +} + +// SetProof gets a reference to the given VerifiableCredentialProof and assigns it to the Proof field. +func (o *CreateVerifiableCredentialRequestBody) SetProof(v VerifiableCredentialProof) { + o.Proof = &v +} + +// GetTypes returns the Types field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetTypes() []string { + if o == nil || o.Types == nil { + var ret []string + return ret + } + return o.Types +} + +// GetTypesOk returns a tuple with the Types field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetTypesOk() ([]string, bool) { + if o == nil || o.Types == nil { + return nil, false + } + return o.Types, true +} + +// HasTypes returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasTypes() bool { + if o != nil && o.Types != nil { + return true + } + + return false +} + +// SetTypes gets a reference to the given []string and assigns it to the Types field. +func (o *CreateVerifiableCredentialRequestBody) SetTypes(v []string) { + o.Types = v +} + +func (o CreateVerifiableCredentialRequestBody) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Format != nil { + toSerialize["format"] = o.Format + } + if o.Proof != nil { + toSerialize["proof"] = o.Proof + } + if o.Types != nil { + toSerialize["types"] = o.Types + } + return json.Marshal(toSerialize) +} + +type NullableCreateVerifiableCredentialRequestBody struct { + value *CreateVerifiableCredentialRequestBody + isSet bool +} + +func (v NullableCreateVerifiableCredentialRequestBody) Get() *CreateVerifiableCredentialRequestBody { + return v.value +} + +func (v *NullableCreateVerifiableCredentialRequestBody) Set(val *CreateVerifiableCredentialRequestBody) { + v.value = val + v.isSet = true +} + +func (v NullableCreateVerifiableCredentialRequestBody) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateVerifiableCredentialRequestBody) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateVerifiableCredentialRequestBody(val *CreateVerifiableCredentialRequestBody) *NullableCreateVerifiableCredentialRequestBody { + return &NullableCreateVerifiableCredentialRequestBody{value: val, isSet: true} +} + +func (v NullableCreateVerifiableCredentialRequestBody) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateVerifiableCredentialRequestBody) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_credential_supported_draft00.go b/internal/httpclient/model_credential_supported_draft00.go new file mode 100644 index 0000000000..f95e03ca9f --- /dev/null +++ b/internal/httpclient/model_credential_supported_draft00.go @@ -0,0 +1,226 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// CredentialSupportedDraft00 Includes information about the supported verifiable credentials. +type CredentialSupportedDraft00 struct { + // OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported Contains a list of cryptographic binding methods supported for signing the proof. + CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported,omitempty"` + // OpenID Connect Verifiable Credentials Cryptographic Suites Supported Contains a list of cryptographic suites methods supported for signing the proof. + CryptographicSuitesSupported []string `json:"cryptographic_suites_supported,omitempty"` + // OpenID Connect Verifiable Credentials Format Contains the format that is supported by this authorization server. + Format *string `json:"format,omitempty"` + // OpenID Connect Verifiable Credentials Types Contains the types of verifiable credentials supported. + Types []string `json:"types,omitempty"` +} + +// NewCredentialSupportedDraft00 instantiates a new CredentialSupportedDraft00 object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCredentialSupportedDraft00() *CredentialSupportedDraft00 { + this := CredentialSupportedDraft00{} + return &this +} + +// NewCredentialSupportedDraft00WithDefaults instantiates a new CredentialSupportedDraft00 object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCredentialSupportedDraft00WithDefaults() *CredentialSupportedDraft00 { + this := CredentialSupportedDraft00{} + return &this +} + +// GetCryptographicBindingMethodsSupported returns the CryptographicBindingMethodsSupported field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupported() []string { + if o == nil || o.CryptographicBindingMethodsSupported == nil { + var ret []string + return ret + } + return o.CryptographicBindingMethodsSupported +} + +// GetCryptographicBindingMethodsSupportedOk returns a tuple with the CryptographicBindingMethodsSupported field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupportedOk() ([]string, bool) { + if o == nil || o.CryptographicBindingMethodsSupported == nil { + return nil, false + } + return o.CryptographicBindingMethodsSupported, true +} + +// HasCryptographicBindingMethodsSupported returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasCryptographicBindingMethodsSupported() bool { + if o != nil && o.CryptographicBindingMethodsSupported != nil { + return true + } + + return false +} + +// SetCryptographicBindingMethodsSupported gets a reference to the given []string and assigns it to the CryptographicBindingMethodsSupported field. +func (o *CredentialSupportedDraft00) SetCryptographicBindingMethodsSupported(v []string) { + o.CryptographicBindingMethodsSupported = v +} + +// GetCryptographicSuitesSupported returns the CryptographicSuitesSupported field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupported() []string { + if o == nil || o.CryptographicSuitesSupported == nil { + var ret []string + return ret + } + return o.CryptographicSuitesSupported +} + +// GetCryptographicSuitesSupportedOk returns a tuple with the CryptographicSuitesSupported field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupportedOk() ([]string, bool) { + if o == nil || o.CryptographicSuitesSupported == nil { + return nil, false + } + return o.CryptographicSuitesSupported, true +} + +// HasCryptographicSuitesSupported returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasCryptographicSuitesSupported() bool { + if o != nil && o.CryptographicSuitesSupported != nil { + return true + } + + return false +} + +// SetCryptographicSuitesSupported gets a reference to the given []string and assigns it to the CryptographicSuitesSupported field. +func (o *CredentialSupportedDraft00) SetCryptographicSuitesSupported(v []string) { + o.CryptographicSuitesSupported = v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetFormat() string { + if o == nil || o.Format == nil { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetFormatOk() (*string, bool) { + if o == nil || o.Format == nil { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasFormat() bool { + if o != nil && o.Format != nil { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *CredentialSupportedDraft00) SetFormat(v string) { + o.Format = &v +} + +// GetTypes returns the Types field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetTypes() []string { + if o == nil || o.Types == nil { + var ret []string + return ret + } + return o.Types +} + +// GetTypesOk returns a tuple with the Types field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetTypesOk() ([]string, bool) { + if o == nil || o.Types == nil { + return nil, false + } + return o.Types, true +} + +// HasTypes returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasTypes() bool { + if o != nil && o.Types != nil { + return true + } + + return false +} + +// SetTypes gets a reference to the given []string and assigns it to the Types field. +func (o *CredentialSupportedDraft00) SetTypes(v []string) { + o.Types = v +} + +func (o CredentialSupportedDraft00) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.CryptographicBindingMethodsSupported != nil { + toSerialize["cryptographic_binding_methods_supported"] = o.CryptographicBindingMethodsSupported + } + if o.CryptographicSuitesSupported != nil { + toSerialize["cryptographic_suites_supported"] = o.CryptographicSuitesSupported + } + if o.Format != nil { + toSerialize["format"] = o.Format + } + if o.Types != nil { + toSerialize["types"] = o.Types + } + return json.Marshal(toSerialize) +} + +type NullableCredentialSupportedDraft00 struct { + value *CredentialSupportedDraft00 + isSet bool +} + +func (v NullableCredentialSupportedDraft00) Get() *CredentialSupportedDraft00 { + return v.value +} + +func (v *NullableCredentialSupportedDraft00) Set(val *CredentialSupportedDraft00) { + v.value = val + v.isSet = true +} + +func (v NullableCredentialSupportedDraft00) IsSet() bool { + return v.isSet +} + +func (v *NullableCredentialSupportedDraft00) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCredentialSupportedDraft00(val *CredentialSupportedDraft00) *NullableCredentialSupportedDraft00 { + return &NullableCredentialSupportedDraft00{value: val, isSet: true} +} + +func (v NullableCredentialSupportedDraft00) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCredentialSupportedDraft00) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_oidc_configuration.go b/internal/httpclient/model_oidc_configuration.go index 78411e52b7..08a0e7cd90 100644 --- a/internal/httpclient/model_oidc_configuration.go +++ b/internal/httpclient/model_oidc_configuration.go @@ -29,6 +29,10 @@ type OidcConfiguration struct { ClaimsSupported []string `json:"claims_supported,omitempty"` // OAuth 2.0 PKCE Supported Code Challenge Methods JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported by this authorization server. CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"` + // OpenID Connect Verifiable Credentials Endpoint Contains the URL of the Verifiable Credentials Endpoint. + CredentialsEndpointDraft00 *string `json:"credentials_endpoint_draft_00,omitempty"` + // OpenID Connect Verifiable Credentials Supported JSON array containing a list of the Verifiable Credentials supported by this authorization server. + CredentialsSupportedDraft00 []CredentialSupportedDraft00 `json:"credentials_supported_draft_00,omitempty"` // OpenID Connect End-Session Endpoint URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP. EndSessionEndpoint *string `json:"end_session_endpoint,omitempty"` // OpenID Connect Front-Channel Logout Session Required Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to identify the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also included in ID Tokens issued by the OP. @@ -287,6 +291,70 @@ func (o *OidcConfiguration) SetCodeChallengeMethodsSupported(v []string) { o.CodeChallengeMethodsSupported = v } +// GetCredentialsEndpointDraft00 returns the CredentialsEndpointDraft00 field value if set, zero value otherwise. +func (o *OidcConfiguration) GetCredentialsEndpointDraft00() string { + if o == nil || o.CredentialsEndpointDraft00 == nil { + var ret string + return ret + } + return *o.CredentialsEndpointDraft00 +} + +// GetCredentialsEndpointDraft00Ok returns a tuple with the CredentialsEndpointDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OidcConfiguration) GetCredentialsEndpointDraft00Ok() (*string, bool) { + if o == nil || o.CredentialsEndpointDraft00 == nil { + return nil, false + } + return o.CredentialsEndpointDraft00, true +} + +// HasCredentialsEndpointDraft00 returns a boolean if a field has been set. +func (o *OidcConfiguration) HasCredentialsEndpointDraft00() bool { + if o != nil && o.CredentialsEndpointDraft00 != nil { + return true + } + + return false +} + +// SetCredentialsEndpointDraft00 gets a reference to the given string and assigns it to the CredentialsEndpointDraft00 field. +func (o *OidcConfiguration) SetCredentialsEndpointDraft00(v string) { + o.CredentialsEndpointDraft00 = &v +} + +// GetCredentialsSupportedDraft00 returns the CredentialsSupportedDraft00 field value if set, zero value otherwise. +func (o *OidcConfiguration) GetCredentialsSupportedDraft00() []CredentialSupportedDraft00 { + if o == nil || o.CredentialsSupportedDraft00 == nil { + var ret []CredentialSupportedDraft00 + return ret + } + return o.CredentialsSupportedDraft00 +} + +// GetCredentialsSupportedDraft00Ok returns a tuple with the CredentialsSupportedDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OidcConfiguration) GetCredentialsSupportedDraft00Ok() ([]CredentialSupportedDraft00, bool) { + if o == nil || o.CredentialsSupportedDraft00 == nil { + return nil, false + } + return o.CredentialsSupportedDraft00, true +} + +// HasCredentialsSupportedDraft00 returns a boolean if a field has been set. +func (o *OidcConfiguration) HasCredentialsSupportedDraft00() bool { + if o != nil && o.CredentialsSupportedDraft00 != nil { + return true + } + + return false +} + +// SetCredentialsSupportedDraft00 gets a reference to the given []CredentialSupportedDraft00 and assigns it to the CredentialsSupportedDraft00 field. +func (o *OidcConfiguration) SetCredentialsSupportedDraft00(v []CredentialSupportedDraft00) { + o.CredentialsSupportedDraft00 = v +} + // GetEndSessionEndpoint returns the EndSessionEndpoint field value if set, zero value otherwise. func (o *OidcConfiguration) GetEndSessionEndpoint() string { if o == nil || o.EndSessionEndpoint == nil { @@ -979,6 +1047,12 @@ func (o OidcConfiguration) MarshalJSON() ([]byte, error) { if o.CodeChallengeMethodsSupported != nil { toSerialize["code_challenge_methods_supported"] = o.CodeChallengeMethodsSupported } + if o.CredentialsEndpointDraft00 != nil { + toSerialize["credentials_endpoint_draft_00"] = o.CredentialsEndpointDraft00 + } + if o.CredentialsSupportedDraft00 != nil { + toSerialize["credentials_supported_draft_00"] = o.CredentialsSupportedDraft00 + } if o.EndSessionEndpoint != nil { toSerialize["end_session_endpoint"] = o.EndSessionEndpoint } diff --git a/internal/httpclient/model_rfc6749_error_json.go b/internal/httpclient/model_rfc6749_error_json.go new file mode 100644 index 0000000000..cf9ffb3691 --- /dev/null +++ b/internal/httpclient/model_rfc6749_error_json.go @@ -0,0 +1,258 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// RFC6749ErrorJson struct for RFC6749ErrorJson +type RFC6749ErrorJson struct { + Error *string `json:"error,omitempty"` + ErrorDebug *string `json:"error_debug,omitempty"` + ErrorDescription *string `json:"error_description,omitempty"` + ErrorHint *string `json:"error_hint,omitempty"` + StatusCode *int64 `json:"status_code,omitempty"` +} + +// NewRFC6749ErrorJson instantiates a new RFC6749ErrorJson object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewRFC6749ErrorJson() *RFC6749ErrorJson { + this := RFC6749ErrorJson{} + return &this +} + +// NewRFC6749ErrorJsonWithDefaults instantiates a new RFC6749ErrorJson object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewRFC6749ErrorJsonWithDefaults() *RFC6749ErrorJson { + this := RFC6749ErrorJson{} + return &this +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetError() string { + if o == nil || o.Error == nil { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorOk() (*string, bool) { + if o == nil || o.Error == nil { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasError() bool { + if o != nil && o.Error != nil { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *RFC6749ErrorJson) SetError(v string) { + o.Error = &v +} + +// GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorDebug() string { + if o == nil || o.ErrorDebug == nil { + var ret string + return ret + } + return *o.ErrorDebug +} + +// GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorDebugOk() (*string, bool) { + if o == nil || o.ErrorDebug == nil { + return nil, false + } + return o.ErrorDebug, true +} + +// HasErrorDebug returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorDebug() bool { + if o != nil && o.ErrorDebug != nil { + return true + } + + return false +} + +// SetErrorDebug gets a reference to the given string and assigns it to the ErrorDebug field. +func (o *RFC6749ErrorJson) SetErrorDebug(v string) { + o.ErrorDebug = &v +} + +// GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorDescription() string { + if o == nil || o.ErrorDescription == nil { + var ret string + return ret + } + return *o.ErrorDescription +} + +// GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorDescriptionOk() (*string, bool) { + if o == nil || o.ErrorDescription == nil { + return nil, false + } + return o.ErrorDescription, true +} + +// HasErrorDescription returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorDescription() bool { + if o != nil && o.ErrorDescription != nil { + return true + } + + return false +} + +// SetErrorDescription gets a reference to the given string and assigns it to the ErrorDescription field. +func (o *RFC6749ErrorJson) SetErrorDescription(v string) { + o.ErrorDescription = &v +} + +// GetErrorHint returns the ErrorHint field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorHint() string { + if o == nil || o.ErrorHint == nil { + var ret string + return ret + } + return *o.ErrorHint +} + +// GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorHintOk() (*string, bool) { + if o == nil || o.ErrorHint == nil { + return nil, false + } + return o.ErrorHint, true +} + +// HasErrorHint returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorHint() bool { + if o != nil && o.ErrorHint != nil { + return true + } + + return false +} + +// SetErrorHint gets a reference to the given string and assigns it to the ErrorHint field. +func (o *RFC6749ErrorJson) SetErrorHint(v string) { + o.ErrorHint = &v +} + +// GetStatusCode returns the StatusCode field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetStatusCode() int64 { + if o == nil || o.StatusCode == nil { + var ret int64 + return ret + } + return *o.StatusCode +} + +// GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetStatusCodeOk() (*int64, bool) { + if o == nil || o.StatusCode == nil { + return nil, false + } + return o.StatusCode, true +} + +// HasStatusCode returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasStatusCode() bool { + if o != nil && o.StatusCode != nil { + return true + } + + return false +} + +// SetStatusCode gets a reference to the given int64 and assigns it to the StatusCode field. +func (o *RFC6749ErrorJson) SetStatusCode(v int64) { + o.StatusCode = &v +} + +func (o RFC6749ErrorJson) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Error != nil { + toSerialize["error"] = o.Error + } + if o.ErrorDebug != nil { + toSerialize["error_debug"] = o.ErrorDebug + } + if o.ErrorDescription != nil { + toSerialize["error_description"] = o.ErrorDescription + } + if o.ErrorHint != nil { + toSerialize["error_hint"] = o.ErrorHint + } + if o.StatusCode != nil { + toSerialize["status_code"] = o.StatusCode + } + return json.Marshal(toSerialize) +} + +type NullableRFC6749ErrorJson struct { + value *RFC6749ErrorJson + isSet bool +} + +func (v NullableRFC6749ErrorJson) Get() *RFC6749ErrorJson { + return v.value +} + +func (v *NullableRFC6749ErrorJson) Set(val *RFC6749ErrorJson) { + v.value = val + v.isSet = true +} + +func (v NullableRFC6749ErrorJson) IsSet() bool { + return v.isSet +} + +func (v *NullableRFC6749ErrorJson) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRFC6749ErrorJson(val *RFC6749ErrorJson) *NullableRFC6749ErrorJson { + return &NullableRFC6749ErrorJson{value: val, isSet: true} +} + +func (v NullableRFC6749ErrorJson) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRFC6749ErrorJson) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verifiable_credential_priming_response.go b/internal/httpclient/model_verifiable_credential_priming_response.go new file mode 100644 index 0000000000..0744fd0704 --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_priming_response.go @@ -0,0 +1,366 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// VerifiableCredentialPrimingResponse struct for VerifiableCredentialPrimingResponse +type VerifiableCredentialPrimingResponse struct { + CNonce *string `json:"c_nonce,omitempty"` + CNonceExpiresIn *int64 `json:"c_nonce_expires_in,omitempty"` + Error *string `json:"error,omitempty"` + ErrorDebug *string `json:"error_debug,omitempty"` + ErrorDescription *string `json:"error_description,omitempty"` + ErrorHint *string `json:"error_hint,omitempty"` + Format *string `json:"format,omitempty"` + StatusCode *int64 `json:"status_code,omitempty"` +} + +// NewVerifiableCredentialPrimingResponse instantiates a new VerifiableCredentialPrimingResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialPrimingResponse() *VerifiableCredentialPrimingResponse { + this := VerifiableCredentialPrimingResponse{} + return &this +} + +// NewVerifiableCredentialPrimingResponseWithDefaults instantiates a new VerifiableCredentialPrimingResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialPrimingResponseWithDefaults() *VerifiableCredentialPrimingResponse { + this := VerifiableCredentialPrimingResponse{} + return &this +} + +// GetCNonce returns the CNonce field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetCNonce() string { + if o == nil || o.CNonce == nil { + var ret string + return ret + } + return *o.CNonce +} + +// GetCNonceOk returns a tuple with the CNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetCNonceOk() (*string, bool) { + if o == nil || o.CNonce == nil { + return nil, false + } + return o.CNonce, true +} + +// HasCNonce returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasCNonce() bool { + if o != nil && o.CNonce != nil { + return true + } + + return false +} + +// SetCNonce gets a reference to the given string and assigns it to the CNonce field. +func (o *VerifiableCredentialPrimingResponse) SetCNonce(v string) { + o.CNonce = &v +} + +// GetCNonceExpiresIn returns the CNonceExpiresIn field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresIn() int64 { + if o == nil || o.CNonceExpiresIn == nil { + var ret int64 + return ret + } + return *o.CNonceExpiresIn +} + +// GetCNonceExpiresInOk returns a tuple with the CNonceExpiresIn field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresInOk() (*int64, bool) { + if o == nil || o.CNonceExpiresIn == nil { + return nil, false + } + return o.CNonceExpiresIn, true +} + +// HasCNonceExpiresIn returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasCNonceExpiresIn() bool { + if o != nil && o.CNonceExpiresIn != nil { + return true + } + + return false +} + +// SetCNonceExpiresIn gets a reference to the given int64 and assigns it to the CNonceExpiresIn field. +func (o *VerifiableCredentialPrimingResponse) SetCNonceExpiresIn(v int64) { + o.CNonceExpiresIn = &v +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetError() string { + if o == nil || o.Error == nil { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorOk() (*string, bool) { + if o == nil || o.Error == nil { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasError() bool { + if o != nil && o.Error != nil { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *VerifiableCredentialPrimingResponse) SetError(v string) { + o.Error = &v +} + +// GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorDebug() string { + if o == nil || o.ErrorDebug == nil { + var ret string + return ret + } + return *o.ErrorDebug +} + +// GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorDebugOk() (*string, bool) { + if o == nil || o.ErrorDebug == nil { + return nil, false + } + return o.ErrorDebug, true +} + +// HasErrorDebug returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorDebug() bool { + if o != nil && o.ErrorDebug != nil { + return true + } + + return false +} + +// SetErrorDebug gets a reference to the given string and assigns it to the ErrorDebug field. +func (o *VerifiableCredentialPrimingResponse) SetErrorDebug(v string) { + o.ErrorDebug = &v +} + +// GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorDescription() string { + if o == nil || o.ErrorDescription == nil { + var ret string + return ret + } + return *o.ErrorDescription +} + +// GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorDescriptionOk() (*string, bool) { + if o == nil || o.ErrorDescription == nil { + return nil, false + } + return o.ErrorDescription, true +} + +// HasErrorDescription returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorDescription() bool { + if o != nil && o.ErrorDescription != nil { + return true + } + + return false +} + +// SetErrorDescription gets a reference to the given string and assigns it to the ErrorDescription field. +func (o *VerifiableCredentialPrimingResponse) SetErrorDescription(v string) { + o.ErrorDescription = &v +} + +// GetErrorHint returns the ErrorHint field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorHint() string { + if o == nil || o.ErrorHint == nil { + var ret string + return ret + } + return *o.ErrorHint +} + +// GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorHintOk() (*string, bool) { + if o == nil || o.ErrorHint == nil { + return nil, false + } + return o.ErrorHint, true +} + +// HasErrorHint returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorHint() bool { + if o != nil && o.ErrorHint != nil { + return true + } + + return false +} + +// SetErrorHint gets a reference to the given string and assigns it to the ErrorHint field. +func (o *VerifiableCredentialPrimingResponse) SetErrorHint(v string) { + o.ErrorHint = &v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetFormat() string { + if o == nil || o.Format == nil { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetFormatOk() (*string, bool) { + if o == nil || o.Format == nil { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasFormat() bool { + if o != nil && o.Format != nil { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *VerifiableCredentialPrimingResponse) SetFormat(v string) { + o.Format = &v +} + +// GetStatusCode returns the StatusCode field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetStatusCode() int64 { + if o == nil || o.StatusCode == nil { + var ret int64 + return ret + } + return *o.StatusCode +} + +// GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetStatusCodeOk() (*int64, bool) { + if o == nil || o.StatusCode == nil { + return nil, false + } + return o.StatusCode, true +} + +// HasStatusCode returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasStatusCode() bool { + if o != nil && o.StatusCode != nil { + return true + } + + return false +} + +// SetStatusCode gets a reference to the given int64 and assigns it to the StatusCode field. +func (o *VerifiableCredentialPrimingResponse) SetStatusCode(v int64) { + o.StatusCode = &v +} + +func (o VerifiableCredentialPrimingResponse) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.CNonce != nil { + toSerialize["c_nonce"] = o.CNonce + } + if o.CNonceExpiresIn != nil { + toSerialize["c_nonce_expires_in"] = o.CNonceExpiresIn + } + if o.Error != nil { + toSerialize["error"] = o.Error + } + if o.ErrorDebug != nil { + toSerialize["error_debug"] = o.ErrorDebug + } + if o.ErrorDescription != nil { + toSerialize["error_description"] = o.ErrorDescription + } + if o.ErrorHint != nil { + toSerialize["error_hint"] = o.ErrorHint + } + if o.Format != nil { + toSerialize["format"] = o.Format + } + if o.StatusCode != nil { + toSerialize["status_code"] = o.StatusCode + } + return json.Marshal(toSerialize) +} + +type NullableVerifiableCredentialPrimingResponse struct { + value *VerifiableCredentialPrimingResponse + isSet bool +} + +func (v NullableVerifiableCredentialPrimingResponse) Get() *VerifiableCredentialPrimingResponse { + return v.value +} + +func (v *NullableVerifiableCredentialPrimingResponse) Set(val *VerifiableCredentialPrimingResponse) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialPrimingResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialPrimingResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialPrimingResponse(val *VerifiableCredentialPrimingResponse) *NullableVerifiableCredentialPrimingResponse { + return &NullableVerifiableCredentialPrimingResponse{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialPrimingResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialPrimingResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verifiable_credential_proof.go b/internal/httpclient/model_verifiable_credential_proof.go new file mode 100644 index 0000000000..0e9bdf78a5 --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_proof.go @@ -0,0 +1,150 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// VerifiableCredentialProof struct for VerifiableCredentialProof +type VerifiableCredentialProof struct { + Jwt *string `json:"jwt,omitempty"` + ProofType *string `json:"proof_type,omitempty"` +} + +// NewVerifiableCredentialProof instantiates a new VerifiableCredentialProof object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialProof() *VerifiableCredentialProof { + this := VerifiableCredentialProof{} + return &this +} + +// NewVerifiableCredentialProofWithDefaults instantiates a new VerifiableCredentialProof object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialProofWithDefaults() *VerifiableCredentialProof { + this := VerifiableCredentialProof{} + return &this +} + +// GetJwt returns the Jwt field value if set, zero value otherwise. +func (o *VerifiableCredentialProof) GetJwt() string { + if o == nil || o.Jwt == nil { + var ret string + return ret + } + return *o.Jwt +} + +// GetJwtOk returns a tuple with the Jwt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialProof) GetJwtOk() (*string, bool) { + if o == nil || o.Jwt == nil { + return nil, false + } + return o.Jwt, true +} + +// HasJwt returns a boolean if a field has been set. +func (o *VerifiableCredentialProof) HasJwt() bool { + if o != nil && o.Jwt != nil { + return true + } + + return false +} + +// SetJwt gets a reference to the given string and assigns it to the Jwt field. +func (o *VerifiableCredentialProof) SetJwt(v string) { + o.Jwt = &v +} + +// GetProofType returns the ProofType field value if set, zero value otherwise. +func (o *VerifiableCredentialProof) GetProofType() string { + if o == nil || o.ProofType == nil { + var ret string + return ret + } + return *o.ProofType +} + +// GetProofTypeOk returns a tuple with the ProofType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialProof) GetProofTypeOk() (*string, bool) { + if o == nil || o.ProofType == nil { + return nil, false + } + return o.ProofType, true +} + +// HasProofType returns a boolean if a field has been set. +func (o *VerifiableCredentialProof) HasProofType() bool { + if o != nil && o.ProofType != nil { + return true + } + + return false +} + +// SetProofType gets a reference to the given string and assigns it to the ProofType field. +func (o *VerifiableCredentialProof) SetProofType(v string) { + o.ProofType = &v +} + +func (o VerifiableCredentialProof) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Jwt != nil { + toSerialize["jwt"] = o.Jwt + } + if o.ProofType != nil { + toSerialize["proof_type"] = o.ProofType + } + return json.Marshal(toSerialize) +} + +type NullableVerifiableCredentialProof struct { + value *VerifiableCredentialProof + isSet bool +} + +func (v NullableVerifiableCredentialProof) Get() *VerifiableCredentialProof { + return v.value +} + +func (v *NullableVerifiableCredentialProof) Set(val *VerifiableCredentialProof) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialProof) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialProof) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialProof(val *VerifiableCredentialProof) *NullableVerifiableCredentialProof { + return &NullableVerifiableCredentialProof{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialProof) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialProof) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verifiable_credential_response.go b/internal/httpclient/model_verifiable_credential_response.go new file mode 100644 index 0000000000..a1296ee5bc --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_response.go @@ -0,0 +1,150 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// VerifiableCredentialResponse struct for VerifiableCredentialResponse +type VerifiableCredentialResponse struct { + CredentialDraft00 *string `json:"credential_draft_00,omitempty"` + Format *string `json:"format,omitempty"` +} + +// NewVerifiableCredentialResponse instantiates a new VerifiableCredentialResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialResponse() *VerifiableCredentialResponse { + this := VerifiableCredentialResponse{} + return &this +} + +// NewVerifiableCredentialResponseWithDefaults instantiates a new VerifiableCredentialResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialResponseWithDefaults() *VerifiableCredentialResponse { + this := VerifiableCredentialResponse{} + return &this +} + +// GetCredentialDraft00 returns the CredentialDraft00 field value if set, zero value otherwise. +func (o *VerifiableCredentialResponse) GetCredentialDraft00() string { + if o == nil || o.CredentialDraft00 == nil { + var ret string + return ret + } + return *o.CredentialDraft00 +} + +// GetCredentialDraft00Ok returns a tuple with the CredentialDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialResponse) GetCredentialDraft00Ok() (*string, bool) { + if o == nil || o.CredentialDraft00 == nil { + return nil, false + } + return o.CredentialDraft00, true +} + +// HasCredentialDraft00 returns a boolean if a field has been set. +func (o *VerifiableCredentialResponse) HasCredentialDraft00() bool { + if o != nil && o.CredentialDraft00 != nil { + return true + } + + return false +} + +// SetCredentialDraft00 gets a reference to the given string and assigns it to the CredentialDraft00 field. +func (o *VerifiableCredentialResponse) SetCredentialDraft00(v string) { + o.CredentialDraft00 = &v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *VerifiableCredentialResponse) GetFormat() string { + if o == nil || o.Format == nil { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialResponse) GetFormatOk() (*string, bool) { + if o == nil || o.Format == nil { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *VerifiableCredentialResponse) HasFormat() bool { + if o != nil && o.Format != nil { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *VerifiableCredentialResponse) SetFormat(v string) { + o.Format = &v +} + +func (o VerifiableCredentialResponse) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.CredentialDraft00 != nil { + toSerialize["credential_draft_00"] = o.CredentialDraft00 + } + if o.Format != nil { + toSerialize["format"] = o.Format + } + return json.Marshal(toSerialize) +} + +type NullableVerifiableCredentialResponse struct { + value *VerifiableCredentialResponse + isSet bool +} + +func (v NullableVerifiableCredentialResponse) Get() *VerifiableCredentialResponse { + return v.value +} + +func (v *NullableVerifiableCredentialResponse) Set(val *VerifiableCredentialResponse) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialResponse(val *VerifiableCredentialResponse) *NullableVerifiableCredentialResponse { + return &NullableVerifiableCredentialResponse{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json index 330e25c43a..215fa01821 100644 --- a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json +++ b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json @@ -10,6 +10,31 @@ "plain", "S256" ], + "credentials_endpoint_draft_00": "http://hydra.localhost/credentials", + "credentials_supported_draft_00": [ + { + "cryptographic_binding_methods_supported": [ + "jwk" + ], + "cryptographic_suites_supported": [ + "PS256", + "RS256", + "ES256", + "PS384", + "RS384", + "ES384", + "PS512", + "RS512", + "ES512", + "EdDSA" + ], + "format": "jwt_vc_json", + "types": [ + "VerifiableCredential", + "UserInfoCredential" + ] + } + ], "end_session_endpoint": "http://hydra.localhost/oauth2/sessions/logout", "frontchannel_logout_session_supported": true, "frontchannel_logout_supported": true, diff --git a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json index 330e25c43a..215fa01821 100644 --- a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json +++ b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json @@ -10,6 +10,31 @@ "plain", "S256" ], + "credentials_endpoint_draft_00": "http://hydra.localhost/credentials", + "credentials_supported_draft_00": [ + { + "cryptographic_binding_methods_supported": [ + "jwk" + ], + "cryptographic_suites_supported": [ + "PS256", + "RS256", + "ES256", + "PS384", + "RS384", + "ES384", + "PS512", + "RS512", + "ES512", + "EdDSA" + ], + "format": "jwt_vc_json", + "types": [ + "VerifiableCredential", + "UserInfoCredential" + ] + } + ], "end_session_endpoint": "http://hydra.localhost/oauth2/sessions/logout", "frontchannel_logout_session_supported": true, "frontchannel_logout_supported": true, diff --git a/oauth2/handler.go b/oauth2/handler.go index 0cd6d53cb3..f53b17fcad 100644 --- a/oauth2/handler.go +++ b/oauth2/handler.go @@ -4,6 +4,7 @@ package oauth2 import ( + "encoding/base64" "encoding/json" "fmt" "html/template" @@ -12,10 +13,15 @@ import ( "strings" "time" + "github.com/tidwall/gjson" + + "github.com/pborman/uuid" + "github.com/ory/hydra/v2/x/events" "github.com/ory/x/httprouterx" + "github.com/ory/x/josex" - "github.com/pborman/uuid" + jwtV5 "github.com/golang-jwt/jwt/v5" "github.com/ory/x/errorsx" @@ -43,9 +49,10 @@ const ( AuthPath = "/oauth2/auth" LogoutPath = "/oauth2/sessions/logout" - UserinfoPath = "/userinfo" - WellKnownPath = "/.well-known/openid-configuration" - JWKPath = "/.well-known/jwks.json" + VerifiableCredentialsPath = "/credentials" + UserinfoPath = "/userinfo" + WellKnownPath = "/.well-known/openid-configuration" + JWKPath = "/.well-known/jwks.json" // IntrospectPath points to the OAuth2 introspection endpoint. IntrospectPath = "/oauth2/introspect" @@ -93,6 +100,9 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. public.Handler("GET", UserinfoPath, corsMiddleware(http.HandlerFunc(h.getOidcUserInfo))) public.Handler("POST", UserinfoPath, corsMiddleware(http.HandlerFunc(h.getOidcUserInfo))) + public.Handler("OPTIONS", VerifiableCredentialsPath, corsMiddleware(http.HandlerFunc(h.handleOptions))) + public.Handler("POST", VerifiableCredentialsPath, corsMiddleware(http.HandlerFunc(h.createVerifiableCredential))) + admin.POST(IntrospectPath, h.introspectOAuth2Token) admin.DELETE(DeleteTokensPath, h.deleteOAuth2Token) } @@ -112,7 +122,7 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. // // Responses: // 302: emptyResponse -func (h *Handler) performOidcFrontOrBackChannelLogout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) performOidcFrontOrBackChannelLogout(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { ctx := r.Context() handled, err := h.r.ConsentStrategy().HandleOpenIDConnectLogout(ctx, w, r) @@ -404,6 +414,43 @@ type oidcConfiguration struct { // JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported // by this authorization server. CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` + + // OpenID Connect Verifiable Credentials Endpoint + // + // Contains the URL of the Verifiable Credentials Endpoint. + CredentialsEndpointDraft00 string `json:"credentials_endpoint_draft_00"` + + // OpenID Connect Verifiable Credentials Supported + // + // JSON array containing a list of the Verifiable Credentials supported by this authorization server. + CredentialsSupportedDraft00 []CredentialSupportedDraft00 `json:"credentials_supported_draft_00"` +} + +// Verifiable Credentials Metadata (Draft 00) +// +// Includes information about the supported verifiable credentials. +// +// swagger:model credentialSupportedDraft00 +type CredentialSupportedDraft00 struct { + // OpenID Connect Verifiable Credentials Format + // + // Contains the format that is supported by this authorization server. + Format string `json:"format"` + + // OpenID Connect Verifiable Credentials Types + // + // Contains the types of verifiable credentials supported. + Types []string `json:"types"` + + // OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported + // + // Contains a list of cryptographic binding methods supported for signing the proof. + CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported"` + + // OpenID Connect Verifiable Credentials Cryptographic Suites Supported + // + // Contains a list of cryptographic suites methods supported for signing the proof. + CryptographicSuitesSupported []string `json:"cryptographic_suites_supported"` } // swagger:route GET /.well-known/openid-configuration oidc discoverOidcConfiguration @@ -424,23 +471,24 @@ type oidcConfiguration struct { // 200: oidcConfiguration // default: errorOAuth2 func (h *Handler) discoverOidcConfiguration(w http.ResponseWriter, r *http.Request) { - key, err := h.r.OpenIDJWTStrategy().GetPublicKey(r.Context()) + ctx := r.Context() + key, err := h.r.OpenIDJWTStrategy().GetPublicKey(ctx) if err != nil { h.r.Writer().WriteError(w, r, err) return } h.r.Writer().Write(w, r, &oidcConfiguration{ - Issuer: h.c.IssuerURL(r.Context()).String(), - AuthURL: h.c.OAuth2AuthURL(r.Context()).String(), - TokenURL: h.c.OAuth2TokenURL(r.Context()).String(), - JWKsURI: h.c.JWKSURL(r.Context()).String(), - RevocationEndpoint: urlx.AppendPaths(h.c.IssuerURL(r.Context()), RevocationPath).String(), - RegistrationEndpoint: h.c.OAuth2ClientRegistrationURL(r.Context()).String(), - SubjectTypes: h.c.SubjectTypesSupported(r.Context()), + Issuer: h.c.IssuerURL(ctx).String(), + AuthURL: h.c.OAuth2AuthURL(ctx).String(), + TokenURL: h.c.OAuth2TokenURL(ctx).String(), + JWKsURI: h.c.JWKSURL(ctx).String(), + RevocationEndpoint: urlx.AppendPaths(h.c.IssuerURL(ctx), RevocationPath).String(), + RegistrationEndpoint: h.c.OAuth2ClientRegistrationURL(ctx).String(), + SubjectTypes: h.c.SubjectTypesSupported(ctx), ResponseTypes: []string{"code", "code id_token", "id_token", "token id_token", "token", "token id_token code"}, - ClaimsSupported: h.c.OIDCDiscoverySupportedClaims(r.Context()), - ScopesSupported: h.c.OIDCDiscoverySupportedScope(r.Context()), - UserinfoEndpoint: h.c.OIDCDiscoveryUserinfoEndpoint(r.Context()).String(), + ClaimsSupported: h.c.OIDCDiscoverySupportedClaims(ctx), + ScopesSupported: h.c.OIDCDiscoverySupportedScope(ctx), + UserinfoEndpoint: h.c.OIDCDiscoveryUserinfoEndpoint(ctx).String(), TokenEndpointAuthMethodsSupported: []string{"client_secret_post", "client_secret_basic", "private_key_jwt", "none"}, IDTokenSigningAlgValuesSupported: []string{key.Algorithm}, IDTokenSignedResponseAlg: []string{key.Algorithm}, @@ -455,9 +503,21 @@ func (h *Handler) discoverOidcConfiguration(w http.ResponseWriter, r *http.Reque BackChannelLogoutSessionSupported: true, FrontChannelLogoutSupported: true, FrontChannelLogoutSessionSupported: true, - EndSessionEndpoint: urlx.AppendPaths(h.c.IssuerURL(r.Context()), LogoutPath).String(), + EndSessionEndpoint: urlx.AppendPaths(h.c.IssuerURL(ctx), LogoutPath).String(), RequestObjectSigningAlgValuesSupported: []string{"none", "RS256", "ES256"}, CodeChallengeMethodsSupported: []string{"plain", "S256"}, + CredentialsEndpointDraft00: h.c.CredentialsEndpointURL(ctx).String(), + CredentialsSupportedDraft00: []CredentialSupportedDraft00{{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + CryptographicBindingMethodsSupported: []string{"jwk"}, + CryptographicSuitesSupported: []string{ + "PS256", "RS256", "ES256", + "PS384", "RS384", "ES384", + "PS512", "RS512", "ES512", + "EdDSA", + }, + }}, }) } @@ -608,7 +668,7 @@ func (h *Handler) getOidcUserInfo(w http.ResponseWriter, r *http.Request) { return } - token, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, jwt.MapClaims(interim), &jwt.Headers{ + token, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, interim, &jwt.Headers{ Extra: map[string]interface{}{"kid": keyID}, }) if err != nil { @@ -1130,7 +1190,7 @@ func (h *Handler) deleteOAuth2Token(w http.ResponseWriter, r *http.Request, _ ht // This function will not be called, OPTIONS request will be handled by cors // this is just a placeholder. -func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) {} +func (h *Handler) handleOptions(http.ResponseWriter, *http.Request) {} func (h *Handler) forwardError(w http.ResponseWriter, r *http.Request, err error) { rfcErr := fosite.ErrorToRFC6749Error(err).WithExposeDebug(h.c.GetSendDebugMessagesToClients(r.Context())) @@ -1154,3 +1214,184 @@ func (h *Handler) logOrAudit(err error, r *http.Request) { x.LogAudit(r, err, h.r.Logger()) } } + +// swagger:route POST /credentials oidc createVerifiableCredential +// +// # Issues a Verifiable Credential +// +// This endpoint creates a verifiable credential that attests that the user +// authenticated with the provided access token owns a certain public/private key +// pair. +// +// More information can be found at +// https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. +// +// Consumes: +// - application/json +// +// Schemes: http, https +// +// Responses: +// 200: verifiableCredentialResponse +// 400: verifiableCredentialPrimingResponse +// default: errorOAuth2 +func (h *Handler) createVerifiableCredential(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session := NewSessionWithCustomClaims("", h.c.AllowedTopLevelClaims(ctx)) + accessToken := fosite.AccessTokenFromRequest(r) + tokenType, _, err := h.r.OAuth2Provider().IntrospectToken(ctx, accessToken, fosite.AccessToken, session) + + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + if tokenType != fosite.AccessToken { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The provided token is not an access token."))) + return + } + + var request CreateVerifiableCredentialRequestBody + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithHint("Unable to decode request body."))) + return + } + + if request.Format != "jwt_vc_json" { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The format %q is not supported.", request.Format))) + return + } + if request.Proof == nil { + // Handle priming request + nonceLifespan := h.r.Config().GetVerifiableCredentialsNonceLifespan(ctx) + nonceExpiresIn := time.Now().Add(nonceLifespan).UTC() + nonce, err := h.r.OAuth2Storage().NewNonce(ctx, accessToken, nonceExpiresIn) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + h.r.Writer().WriteCode(w, r, http.StatusBadRequest, &VerifiableCredentialPrimingResponse{ + RFC6749ErrorJson: fosite.RFC6749ErrorJson{ + Name: "missing_proof", + Description: "Could not issue a verifiable credential because the proof is missing in the request.", + }, + Format: "jwt_vc", + Nonce: nonce, + NonceExpiresIn: int64(nonceLifespan.Seconds()), + }) + return + } + if request.Proof.ProofType != "jwt" { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The proof type %q is not supported.", request.Proof.ProofType))) + return + } + + header, _, ok := strings.Cut(request.Proof.JWT, ".") + if !ok { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT in the proof is malformed."))) + return + } + + rawHeader, err := jwtV5.NewParser().DecodeSegment(header) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT header in the proof is malformed."))) + return + } + jwk := gjson.GetBytes(rawHeader, "jwk").String() + proofJWK, err := josex.LoadJSONWebKey([]byte(jwk), true) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWK in the JWT header is malformed."))) + return + } + + token, err := jwt.Parse(request.Proof.JWT, func(token *jwt.Token) (any, error) { + return proofJWK, nil + }) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT was not signed with the correct key supplied in the JWK header."))) + return + } + + nonce, ok := token.Claims["nonce"].(string) + if !ok { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf(`The JWT did not contain the "nonce" claim.`))) + return + } + + if err = h.r.OAuth2Storage().IsNonceValid(ctx, accessToken, nonce); err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + var response VerifiableCredentialResponse + response.Format = "jwt_vc_json" + + proofJWKJSON, err := json.Marshal(proofJWK) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + + session.Claims.Add("vc", map[string]any{ + "@context": []string{"https://www.w3.org/2018/credentials/v1"}, + "type": []string{"VerifiableCredential", "UserInfoCredential"}, + "credentialSubject": map[string]any{ + // Encode ID according to https://github.com/quartzjer/did-jwk/blob/main/spec.md + "id": fmt.Sprintf("did:jwk:%s", base64.RawURLEncoding.EncodeToString(proofJWKJSON)), + }, + }) + + rawToken, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, session.Claims.ToMapClaims(), jwt.NewHeaders()) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + + response.Credential = rawToken + h.r.Writer().Write(w, r, &response) +} + +// Request a Verifiable Credential +// +// swagger:parameters createVerifiableCredential +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions +type createVerifiableCredentialRequest struct { + // in: body + Body CreateVerifiableCredentialRequestBody +} + +// CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential. +// +// swagger:parameters createVerifiableCredentialRequestBody +type CreateVerifiableCredentialRequestBody struct { + Format string `json:"format"` + Types []string `json:"types"` + Proof *VerifiableCredentialProof `json:"proof"` +} + +// VerifiableCredentialProof contains the proof of a verifiable credential. +// +// swagger:parameters verifiableCredentialProof +type VerifiableCredentialProof struct { + ProofType string `json:"proof_type"` + JWT string `json:"jwt"` +} + +// VerifiableCredentialResponse contains the verifiable credential. +// +// swagger:model verifiableCredentialResponse +type VerifiableCredentialResponse struct { + Format string `json:"format"` + Credential string `json:"credential_draft_00"` +} + +// VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT. +// +// swagger:model verifiableCredentialPrimingResponse +type VerifiableCredentialPrimingResponse struct { + Format string `json:"format"` + Nonce string `json:"c_nonce"` + NonceExpiresIn int64 `json:"c_nonce_expires_in"` + + fosite.RFC6749ErrorJson +} diff --git a/oauth2/oauth2_auth_code_test.go b/oauth2/oauth2_auth_code_test.go index 93349df73e..738b8f8ed4 100644 --- a/oauth2/oauth2_auth_code_test.go +++ b/oauth2/oauth2_auth_code_test.go @@ -6,6 +6,7 @@ package oauth2_test import ( "bytes" "context" + "encoding/base64" "encoding/json" "fmt" "io" @@ -18,9 +19,17 @@ import ( "testing" "time" + "github.com/go-jose/go-jose/v3" + "github.com/golang-jwt/jwt/v5" + + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" "github.com/ory/hydra/v2/flow" + "github.com/ory/x/httpx" "github.com/ory/x/ioutilx" + "github.com/ory/x/josex" "github.com/ory/x/requirex" + "github.com/ory/x/stringsx" hydra "github.com/ory/hydra-client-go/v2" @@ -74,35 +83,14 @@ type clientCreator interface { // - [x] If `id_token_hint` is handled properly // - [x] What happens if `id_token_hint` does not match the value from the handled authentication request ("accept login") func TestAuthCodeWithDefaultStrategy(t *testing.T) { - ctx := context.TODO() + ctx := context.Background() reg := internal.NewMockedRegistry(t, &contextx.Default{}) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") reg.Config().MustSet(ctx, config.KeyRefreshTokenHookURL, "") publicTS, adminTS := testhelpers.NewOAuth2Server(ctx, t, reg) - newOAuth2Client := func(t *testing.T, cb string) (*hc.Client, *oauth2.Config) { - secret := uuid.New() - c := &hc.Client{ - Secret: secret, - RedirectURIs: []string{cb}, - ResponseTypes: []string{"id_token", "code", "token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, - Scope: "hydra offline openid", - Audience: []string{"https://api.ory.sh/"}, - } - require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), c)) - return c, &oauth2.Config{ - ClientID: c.GetID(), - ClientSecret: secret, - Endpoint: oauth2.Endpoint{ - AuthURL: reg.Config().OAuth2AuthURL(ctx).String(), - TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), - AuthStyle: oauth2.AuthStyleInHeader, - }, - Scopes: strings.Split(c.Scope, " "), - } - } - + publicClient := hydra.NewAPIClient(hydra.NewConfiguration()) + publicClient.GetConfig().Servers = hydra.ServerConfigurations{{URL: publicTS.URL}} adminClient := hydra.NewAPIClient(hydra.NewConfiguration()) adminClient.GetConfig().Servers = hydra.ServerConfigurations{{URL: adminTS.URL}} @@ -126,10 +114,10 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { rr, _, err := adminClient.OAuth2Api.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() require.NoError(t, err) - assert.EqualValues(t, c.GetID(), pointerx.StringR(rr.Client.ClientId)) - assert.Empty(t, pointerx.StringR(rr.Client.ClientSecret)) + assert.EqualValues(t, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(t, pointerx.Deref(rr.Client.ClientSecret)) assert.EqualValues(t, c.GrantTypes, rr.Client.GrantTypes) - assert.EqualValues(t, c.LogoURI, pointerx.StringR(rr.Client.LogoUri)) + assert.EqualValues(t, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) assert.EqualValues(t, c.RedirectURIs, rr.Client.RedirectUris) assert.EqualValues(t, r.URL.Query().Get("login_challenge"), rr.Challenge) assert.EqualValues(t, []string{"hydra", "offline", "openid"}, rr.RequestedScope) @@ -137,8 +125,8 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { acceptBody := hydra.AcceptOAuth2LoginRequest{ Subject: subject, - Remember: pointerx.Bool(!rr.Skip), - Acr: pointerx.String("1"), + Remember: pointerx.Ptr(!rr.Skip), + Acr: pointerx.Ptr("1"), Amr: []string{"pwd"}, Context: map[string]interface{}{"context": "bar"}, } @@ -163,12 +151,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { rr, _, err := adminClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() require.NoError(t, err) - assert.EqualValues(t, c.GetID(), pointerx.StringR(rr.Client.ClientId)) - assert.Empty(t, pointerx.StringR(rr.Client.ClientSecret)) + assert.EqualValues(t, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(t, pointerx.Deref(rr.Client.ClientSecret)) assert.EqualValues(t, c.GrantTypes, rr.Client.GrantTypes) - assert.EqualValues(t, c.LogoURI, pointerx.StringR(rr.Client.LogoUri)) + assert.EqualValues(t, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) assert.EqualValues(t, c.RedirectURIs, rr.Client.RedirectUris) - assert.EqualValues(t, subject, pointerx.StringR(rr.Subject)) + assert.EqualValues(t, subject, pointerx.Deref(rr.Subject)) assert.EqualValues(t, []string{"hydra", "offline", "openid"}, rr.RequestedScope) assert.EqualValues(t, r.URL.Query().Get("consent_challenge"), rr.Challenge) assert.Contains(t, *rr.RequestUrl, reg.Config().OAuth2AuthURL(ctx).String()) @@ -180,7 +168,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { v, _, err := adminClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ - GrantScope: []string{"hydra", "offline", "openid"}, Remember: pointerx.Bool(true), RememberFor: pointerx.Int64(0), + GrantScope: []string{"hydra", "offline", "openid"}, Remember: pointerx.Ptr(true), RememberFor: pointerx.Ptr[int64](0), GrantAccessTokenAudience: rr.RequestedAccessTokenAudience, Session: &hydra.AcceptOAuth2ConsentRequestSession{ AccessToken: map[string]interface{}{"foo": "bar"}, @@ -239,7 +227,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { return i } - assertJWTAccessToken := func(t *testing.T, strat string, conf *oauth2.Config, token *oauth2.Token, expectedSubject string, expectedExp time.Time) gjson.Result { + assertJWTAccessToken := func(t *testing.T, strat string, conf *oauth2.Config, token *oauth2.Token, expectedSubject string, expectedExp time.Time, scopes string) gjson.Result { require.NotEmpty(t, token.AccessToken) parts := strings.Split(token.AccessToken, ".") if strat != "jwt" { @@ -261,7 +249,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { assert.True(t, time.Now().Before(time.Unix(i.Get("exp").Int(), 0)), "%s", i) requirex.EqualTime(t, expectedExp, time.Unix(i.Get("exp").Int(), 0), time.Second) assert.EqualValues(t, `bar`, i.Get("ext.foo").String(), "%s", i) - assert.EqualValues(t, `["hydra","offline","openid"]`, i.Get("scp").Raw, "%s", i) + assert.EqualValues(t, scopes, i.Get("scp").Raw, "%s", i) return i } @@ -271,7 +259,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { t.Run("case=checks if request fails when audience does not match", func(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), testhelpers.HTTPServerNoExpectedCallHandler(t), testhelpers.HTTPServerNoExpectedCallHandler(t)) - _, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + _, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) code, _ := getAuthorizeCode(t, conf, nil, oauth2.SetAuthURLParam("audience", "https://not-ory-api/")) require.Empty(t, code) }) @@ -280,7 +268,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { nonce := uuid.New() t.Run("case=perform authorize code flow with ID token and refresh tokens", func(t *testing.T) { run := func(t *testing.T, strategy string) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -292,8 +280,10 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { iat := time.Now() require.NoError(t, err) + assert.Empty(t, token.Extra("c_nonce_draft_00"), "should not be set if not requested") + assert.Empty(t, token.Extra("c_nonce_expires_in_draft_00"), "should not be set if not requested") introspectAccessToken(t, conf, token, subject) - assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx))) + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) assertIDToken(t, token, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) assertRefreshToken(t, token, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) @@ -310,7 +300,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { introspectAccessToken(t, conf, refreshedToken, subject) t.Run("followup=refreshed tokens contain valid tokens", func(t *testing.T) { - assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx))) + assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) assertIDToken(t, refreshedToken, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) assertRefreshToken(t, refreshedToken, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) }) @@ -347,9 +337,190 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) }) + t.Run("case=perform authorize code flow with verifable credentials", func(t *testing.T) { + // Make sure we test against all crypto suites that we advertise. + cfg, _, err := publicClient.OidcApi.DiscoverOidcConfiguration(ctx).Execute() + require.NoError(t, err) + supportedCryptoSuites := cfg.CredentialsSupportedDraft00[0].CryptographicSuitesSupported + + run := func(t *testing.T, strategy string) { + _, conf := newOAuth2Client( + t, + reg, + testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler), + withScope("openid userinfo_credential_draft_00"), + ) + testhelpers.NewLoginConsentUI(t, reg.Config(), + func(w http.ResponseWriter, r *http.Request) { + acceptBody := hydra.AcceptOAuth2LoginRequest{ + Subject: subject, + Acr: pointerx.Ptr("1"), + Amr: []string{"pwd"}, + Context: map[string]interface{}{"context": "bar"}, + } + v, _, err := adminClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + LoginChallenge(r.URL.Query().Get("login_challenge")). + AcceptOAuth2LoginRequest(acceptBody). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }, + func(w http.ResponseWriter, r *http.Request) { + rr, _, err := adminClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + require.NoError(t, err) + + assert.Equal(t, map[string]interface{}{"context": "bar"}, rr.Context) + v, _, err := adminClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). + ConsentChallenge(r.URL.Query().Get("consent_challenge")). + AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ + GrantScope: []string{"openid", "userinfo_credential_draft_00"}, + GrantAccessTokenAudience: rr.RequestedAccessTokenAudience, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + }). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }, + ) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("nonce", nonce), + oauth2.SetAuthURLParam("scope", "openid userinfo_credential_draft_00"), + ) + require.NotEmpty(t, code) + token, err := conf.Exchange(context.Background(), code) + require.NoError(t, err) + iat := time.Now() + + vcNonce := token.Extra("c_nonce_draft_00").(string) + assert.NotEmpty(t, vcNonce) + expiry := token.Extra("c_nonce_expires_in_draft_00") + assert.NotEmpty(t, expiry) + assert.NoError(t, reg.Persister().IsNonceValid(ctx, token.AccessToken, vcNonce)) + + t.Run("followup=successfully create a verifiable credential", func(t *testing.T) { + t.Parallel() + + for _, alg := range supportedCryptoSuites { + alg := alg + t.Run(fmt.Sprintf("alg=%s", alg), func(t *testing.T) { + t.Parallel() + assertCreateVerifiableCredential(t, reg, vcNonce, token, jose.SignatureAlgorithm(alg)) + }) + } + }) + + t.Run("followup=get new nonce from priming request", func(t *testing.T) { + t.Parallel() + // Assert that we can fetch a verifiable credential with the nonce. + res, err := doPrimingRequest(t, reg, token, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + }) + assert.NoError(t, err) + + t.Run("followup=successfully create a verifiable credential from fresh nonce", func(t *testing.T) { + assertCreateVerifiableCredential(t, reg, res.Nonce, token, jose.ES256) + }) + }) + + t.Run("followup=rejects proof signed by another key", func(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + name string + format string + proofType string + proof func() string + }{ + { + name: "proof=mismatching keys", + proof: func() string { + // Create mismatching public and private keys. + pubKey, _, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + _, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid format", + format: "invalid_format", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid type", + proofType: "invalid", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid nonce", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, "invalid nonce") + }, + }, + } { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + _, res := createVerifiableCredential(t, reg, token, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: stringsx.Coalesce(tc.format, "jwt_vc_json"), + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + Proof: &hydraoauth2.VerifiableCredentialProof{ + ProofType: stringsx.Coalesce(tc.proofType, "jwt"), + JWT: tc.proof(), + }, + }) + require.NoError(t, err) + require.NotNil(t, res) + assert.Equal(t, "invalid_request", res.Error()) + }) + } + + }) + + t.Run("followup=access token and id token are valid", func(t *testing.T) { + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["openid","userinfo_credential_draft_00"]`) + assertIDToken(t, token, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) + }) + } + + t.Run("strategy=jwt", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "jwt") + run(t, "jwt") + }) + + t.Run("strategy=opaque", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + run(t, "opaque") + }) + }) + t.Run("suite=invalid query params", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) - otherClient, _ := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + otherClient, _ := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -453,12 +624,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), func(w http.ResponseWriter, r *http.Request) { _, res, err := adminClient.OAuth2Api.AcceptOAuth2LoginRequest(ctx). LoginChallenge(r.URL.Query().Get("login_challenge")). - AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "", Remember: pointerx.Bool(true)}).Execute() + AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "", Remember: pointerx.Ptr(true)}).Execute() require.Error(t, err) // expects 400 body := string(ioutilx.MustReadAll(res.Body)) assert.Contains(t, body, "Field 'subject' must not be empty", "%s", body) }, testhelpers.HTTPServerNoExpectedCallHandler(t)) - _, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + _, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) _, err := testhelpers.NewEmptyJarClient(t).Get(conf.AuthCodeURL(uuid.New())) require.NoError(t, err) @@ -466,7 +637,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { t.Run("case=perform flow with audience", func(t *testing.T) { expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -510,7 +681,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { body := introspectAccessToken(t, conf, token, subject) requirex.EqualTime(t, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration), time.Unix(body.Get("exp").Int(), 0), time.Second) - assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration)) + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration), `["hydra","offline","openid"]`) assertIDToken(t, token, conf, subject, nonce, iat.Add(expectedLifespans.AuthorizationCodeGrantIDTokenLifespan.Duration)) assertRefreshToken(t, token, conf, iat.Add(expectedLifespans.AuthorizationCodeGrantRefreshTokenLifespan.Duration)) @@ -521,7 +692,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { iat = time.Now() require.NoError(t, err) assertRefreshToken(t, refreshedToken, conf, iat.Add(expectedLifespans.RefreshTokenGrantRefreshTokenLifespan.Duration)) - assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(expectedLifespans.RefreshTokenGrantAccessTokenLifespan.Duration)) + assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(expectedLifespans.RefreshTokenGrantAccessTokenLifespan.Duration), `["hydra","offline","openid"]`) assertIDToken(t, refreshedToken, conf, subject, nonce, iat.Add(expectedLifespans.RefreshTokenGrantIDTokenLifespan.Duration)) require.NotEqual(t, token.AccessToken, refreshedToken.AccessToken) @@ -544,7 +715,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { } t.Run("case=custom-lifespans-active-jwt", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) ls := testhelpers.TestLifespans ls.AuthorizationCodeGrantAccessTokenLifespan = x.NullDuration{Valid: true, Duration: 6 * time.Second} testhelpers.UpdateClientTokenLifespans( @@ -558,7 +729,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=custom-lifespans-active-opaque", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) ls := testhelpers.TestLifespans ls.AuthorizationCodeGrantAccessTokenLifespan = x.NullDuration{Valid: true, Duration: 6 * time.Second} testhelpers.UpdateClientTokenLifespans( @@ -572,11 +743,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=custom-lifespans-unset", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.UpdateClientTokenLifespans(t, &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), testhelpers.TestLifespans, adminTS) testhelpers.UpdateClientTokenLifespans(t, &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), hc.Lifespans{}, adminTS) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + //goland:noinspection GoDeprecation expectedLifespans := hc.Lifespans{ AuthorizationCodeGrantAccessTokenLifespan: x.NullDuration{Valid: true, Duration: reg.Config().GetAccessTokenLifespan(ctx)}, AuthorizationCodeGrantIDTokenLifespan: x.NullDuration{Valid: true, Duration: reg.Config().GetIDTokenLifespan(ctx)}, @@ -596,7 +768,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=use remember feature and prompt=none", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -694,7 +866,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=should fail if prompt=none but no auth session given", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -708,7 +880,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=requires re-authentication when id_token_hint is set to a user 'patrik-neu' but the session is 'aeneas-rekkas' and then fails because the user id from the log in endpoint is 'aeneas-rekkas'", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { require.False(t, r.Skip) @@ -732,7 +904,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=should not cause issues if max_age is very low and consent takes a long time", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { time.Sleep(time.Second * 2) @@ -746,7 +918,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=ensure consistent claims returned for userinfo", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -821,7 +993,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { defer reg.Config().MustSet(ctx, config.KeyTokenHookURL, nil) expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -841,7 +1013,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { token, err := conf.Exchange(context.Background(), code) require.NoError(t, err) - assertJWTAccessToken(t, strategy, conf, token, subject, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx))) + assertJWTAccessToken(t, strategy, conf, token, subject, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) // NOTE: using introspect to cover both jwt and opaque strategies accessTokenClaims := introspectAccessToken(t, conf, token, subject) @@ -870,7 +1042,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { defer reg.Config().MustSet(ctx, config.KeyTokenHookURL, nil) expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -910,7 +1082,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { defer reg.Config().MustSet(ctx, config.KeyTokenHookURL, nil) expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -950,7 +1122,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { defer reg.Config().MustSet(ctx, config.KeyTokenHookURL, nil) expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -977,6 +1149,101 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) } +func assertCreateVerifiableCredential(t *testing.T, reg driver.Registry, nonce string, accessToken *oauth2.Token, alg jose.SignatureAlgorithm) { + // Build a proof from the nonce. + pubKey, privKey, err := josex.NewSigningKey(alg, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(alg)} + proofJWT := createVCProofJWT(t, pubKeyJWK, privKey, nonce) + + // Assert that we can fetch a verifiable credential with the nonce. + verifiableCredential, _ := createVerifiableCredential(t, reg, accessToken, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + Proof: &hydraoauth2.VerifiableCredentialProof{ + ProofType: "jwt", + JWT: proofJWT, + }, + }) + require.NoError(t, err) + assertVerifiableCredentialContainsPublicKey(t, reg, verifiableCredential, pubKeyJWK) +} + +func assertVerifiableCredentialContainsPublicKey(t *testing.T, reg driver.Registry, vc *hydraoauth2.VerifiableCredentialResponse, pubKeyJWK *jose.JSONWebKey) { + ctx := context.Background() + token, err := jwt.Parse(vc.Credential, func(token *jwt.Token) (interface{}, error) { + return x.Must(reg.OpenIDJWTStrategy().GetPublicKey(ctx)).Key, nil + }) + require.NoError(t, err) + pubKeyRaw, err := pubKeyJWK.MarshalJSON() + require.NoError(t, err) + expectedID := fmt.Sprintf("did:jwk:%s", base64.RawURLEncoding.EncodeToString(pubKeyRaw)) + require.Equal(t, expectedID, token.Claims.(jwt.MapClaims)["vc"].(map[string]any)["credentialSubject"].(map[string]any)["id"]) +} + +func createVerifiableCredential( + t *testing.T, + reg driver.Registry, + token *oauth2.Token, + createVerifiableCredentialReq *hydraoauth2.CreateVerifiableCredentialRequestBody, +) (vcRes *hydraoauth2.VerifiableCredentialResponse, vcErr *fosite.RFC6749Error) { + var ( + ctx = context.Background() + body bytes.Buffer + ) + require.NoError(t, json.NewEncoder(&body).Encode(createVerifiableCredentialReq)) + req := httpx.MustNewRequest("POST", reg.Config().CredentialsEndpointURL(ctx).String(), &body, "application/json") + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + res, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + var errRes fosite.RFC6749Error + require.NoError(t, json.NewDecoder(res.Body).Decode(&errRes)) + return nil, &errRes + } + require.Equal(t, http.StatusOK, res.StatusCode) + var vc hydraoauth2.VerifiableCredentialResponse + require.NoError(t, json.NewDecoder(res.Body).Decode(&vc)) + + return &vc, vcErr +} + +func doPrimingRequest( + t *testing.T, + reg driver.Registry, + token *oauth2.Token, + createVerifiableCredentialReq *hydraoauth2.CreateVerifiableCredentialRequestBody, +) (*hydraoauth2.VerifiableCredentialPrimingResponse, error) { + var ( + ctx = context.Background() + body bytes.Buffer + ) + require.NoError(t, json.NewEncoder(&body).Encode(createVerifiableCredentialReq)) + req := httpx.MustNewRequest("POST", reg.Config().CredentialsEndpointURL(ctx).String(), &body, "application/json") + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + var vc hydraoauth2.VerifiableCredentialPrimingResponse + require.NoError(t, json.NewDecoder(res.Body).Decode(&vc)) + + return &vc, nil +} + +func createVCProofJWT(t *testing.T, pubKey *jose.JSONWebKey, privKey any, nonce string) string { + proofToken := jwt.NewWithClaims(jwt.GetSigningMethod(string(pubKey.Algorithm)), jwt.MapClaims{"nonce": nonce}) + proofToken.Header["jwk"] = pubKey + proofJWT, err := proofToken.SignedString(privKey) + require.NoError(t, err) + + return proofJWT +} + // TestAuthCodeWithMockStrategy runs the authorization_code flow against various ConsentStrategy scenarios. // For that purpose, the consent strategy is mocked so all scenarios can be applied properly. This test suite checks: // @@ -1059,7 +1326,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, assertAccessToken: func(t *testing.T, token string) { @@ -1110,7 +1377,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, }, @@ -1152,7 +1419,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, }, @@ -1344,7 +1611,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { require.Equal(t, hookReq.Requester.ClientID, oauthConfig.ClientID) require.ElementsMatch(t, hookReq.Requester.GrantedScopes, expectedGrantedScopes) - snapshotx.SnapshotTExcept(t, hookReq, exceptKeys) + snapshotx.SnapshotT(t, hookReq, snapshotx.ExceptPaths(exceptKeys...)) } else { var hookReq hydraoauth2.TokenHookRequest require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) @@ -1357,7 +1624,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { require.ElementsMatch(t, hookReq.Request.GrantedAudience, []string{}) require.Equal(t, hookReq.Request.Payload, map[string][]string{}) - snapshotx.SnapshotTExcept(t, hookReq, exceptKeys) + snapshotx.SnapshotT(t, hookReq, snapshotx.ExceptPaths(exceptKeys...)) } claims := map[string]interface{}{ @@ -1583,3 +1850,53 @@ func testRefresh(t *testing.T, token *oauth2.Token, u string, sleep bool) (*http return http.DefaultClient.Do(req) } + +func withScope(scope string) func(*hc.Client) { + return func(c *hc.Client) { + c.Scope = scope + } +} + +func newOAuth2Client( + t *testing.T, + reg interface { + config.Provider + client.Registry + }, + callbackURL string, + opts ...func(*hc.Client), +) (*hc.Client, *oauth2.Config) { + ctx := context.Background() + secret := uuid.New() + c := &hc.Client{ + Secret: secret, + RedirectURIs: []string{callbackURL}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{ + "implicit", + "refresh_token", + "authorization_code", + "password", + "client_credentials", + }, + Scope: "hydra offline openid", + Audience: []string{"https://api.ory.sh/"}, + } + + // apply options + for _, o := range opts { + o(c) + } + + require.NoError(t, reg.ClientManager().CreateClient(ctx, c)) + return c, &oauth2.Config{ + ClientID: c.GetID(), + ClientSecret: secret, + Endpoint: oauth2.Endpoint{ + AuthURL: reg.Config().OAuth2AuthURL(ctx).String(), + TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), + AuthStyle: oauth2.AuthStyleInHeader, + }, + Scopes: strings.Split(c.Scope, " "), + } +} diff --git a/persistence/sql/persister_nonce.go b/persistence/sql/persister_nonce.go new file mode 100644 index 0000000000..1f4cd76ac0 --- /dev/null +++ b/persistence/sql/persister_nonce.go @@ -0,0 +1,54 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "crypto/sha256" + "time" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" +) + +func accessTokenHash(accessToken string) []byte { + return sha256.New().Sum([]byte(accessToken)) +} + +// Set the aadAccessTokenPrefix to something unique to avoid ciphertext confusion with other usages of the AEAD cipher. +var aadAccessTokenPrefix = "vc-nonce-at:" // nolint:gosec + +func (p *Persister) NewNonce(ctx context.Context, accessToken string, expiresIn time.Time) (res string, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.NewNonce") + defer otelx.End(span, &err) + + plaintext := x.IntToBytes(expiresIn.Unix()) + aad := []byte(aadAccessTokenPrefix + accessToken) + + return p.r.FlowCipher().Encrypt(ctx, plaintext, aad) +} + +func (p *Persister) IsNonceValid(ctx context.Context, accessToken, nonce string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.IsNonceValid") + defer otelx.End(span, &err) + + aad := []byte(aadAccessTokenPrefix + accessToken) + plaintext, err := p.r.FlowCipher().Decrypt(ctx, nonce, aad) + if err != nil { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce is invalid.")) + } + + exp, err := x.BytesToInt(plaintext) + if err != nil { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce is invalid.")) // should never happen + } + + if exp < time.Now().Unix() { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce has expired.")) + } + + return nil +} diff --git a/persistence/sql/persister_nonce_test.go b/persistence/sql/persister_nonce_test.go new file mode 100644 index 0000000000..1de7eda543 --- /dev/null +++ b/persistence/sql/persister_nonce_test.go @@ -0,0 +1,62 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/internal" + "github.com/ory/x/contextx" + "github.com/ory/x/randx" +) + +func TestPersister_Nonce(t *testing.T) { + ctx := context.Background() + p := internal.NewMockedRegistry(t, new(contextx.Default)).Persister() + + accessToken := randx.MustString(100, randx.AlphaNum) + anotherToken := randx.MustString(100, randx.AlphaNum) + validNonce, err := p.NewNonce(ctx, accessToken, time.Now().Add(1*time.Hour)) + require.NoError(t, err) + + expiredNonce, err := p.NewNonce(ctx, accessToken, time.Now().Add(-1*time.Hour)) + require.NoError(t, err) + + nonceForAnotherAccessToken, err := p.NewNonce(ctx, anotherToken, time.Now().Add(-1*time.Hour)) + require.NoError(t, err) + + for _, tc := range []struct { + name string + nonce string + assertErr assert.ErrorAssertionFunc + }{{ + name: "valid nonce", + nonce: validNonce, + assertErr: assert.NoError, + }, { + name: "expired nonce", + nonce: expiredNonce, + assertErr: assertInvalidRequest, + }, { + name: "nonce for another access token", + nonce: nonceForAnotherAccessToken, + assertErr: assertInvalidRequest, + }, + } { + t.Run("case="+tc.name, func(t *testing.T) { + err := p.IsNonceValid(ctx, accessToken, tc.nonce) + tc.assertErr(t, err) + }) + } +} + +func assertInvalidRequest(t assert.TestingT, err error, i ...interface{}) bool { + return assert.ErrorIs(t, err, fosite.ErrInvalidRequest) +} diff --git a/spec/api.json b/spec/api.json index d155f46770..0c4a3d7077 100644 --- a/spec/api.json +++ b/spec/api.json @@ -49,6 +49,24 @@ } }, "schemas": { + "CreateVerifiableCredentialRequestBody": { + "properties": { + "format": { + "type": "string" + }, + "proof": { + "$ref": "#/components/schemas/VerifiableCredentialProof" + }, + "types": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "title": "CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential.", + "type": "object" + }, "DefaultError": {}, "JSONRawMessage": { "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." @@ -81,6 +99,28 @@ "nullable": true, "type": "string" }, + "RFC6749ErrorJson": { + "properties": { + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "status_code": { + "format": "int64", + "type": "integer" + } + }, + "title": "RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error.", + "type": "object" + }, "StringSliceJSONFormat": { "items": { "type": "string" @@ -96,6 +136,18 @@ "format": "uuid4", "type": "string" }, + "VerifiableCredentialProof": { + "properties": { + "jwt": { + "type": "string" + }, + "proof_type": { + "type": "string" + } + }, + "title": "VerifiableCredentialProof contains the proof of a verifiable credential.", + "type": "object" + }, "acceptOAuth2ConsentRequest": { "properties": { "grant_access_token_audience": { @@ -198,6 +250,38 @@ ], "type": "object" }, + "credentialSupportedDraft00": { + "description": "Includes information about the supported verifiable credentials.", + "properties": { + "cryptographic_binding_methods_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported\n\nContains a list of cryptographic binding methods supported for signing the proof.", + "items": { + "type": "string" + }, + "type": "array" + }, + "cryptographic_suites_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Suites Supported\n\nContains a list of cryptographic suites methods supported for signing the proof.", + "items": { + "type": "string" + }, + "type": "array" + }, + "format": { + "description": "OpenID Connect Verifiable Credentials Format\n\nContains the format that is supported by this authorization server.", + "type": "string" + }, + "types": { + "description": "OpenID Connect Verifiable Credentials Types\n\nContains the types of verifiable credentials supported.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "title": "Verifiable Credentials Metadata (Draft 00)", + "type": "object" + }, "errorOAuth2": { "description": "Error", "properties": { @@ -1039,6 +1123,17 @@ }, "type": "array" }, + "credentials_endpoint_draft_00": { + "description": "OpenID Connect Verifiable Credentials Endpoint\n\nContains the URL of the Verifiable Credentials Endpoint.", + "type": "string" + }, + "credentials_supported_draft_00": { + "description": "OpenID Connect Verifiable Credentials Supported\n\nJSON array containing a list of the Verifiable Credentials supported by this authorization server.", + "items": { + "$ref": "#/components/schemas/credentialSupportedDraft00" + }, + "type": "array" + }, "end_session_endpoint": { "description": "OpenID Connect End-Session Endpoint\n\nURL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.", "type": "string" @@ -1513,6 +1608,50 @@ "unexpectedError": { "type": "string" }, + "verifiableCredentialPrimingResponse": { + "properties": { + "c_nonce": { + "type": "string" + }, + "c_nonce_expires_in": { + "format": "int64", + "type": "integer" + }, + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "format": { + "type": "string" + }, + "status_code": { + "format": "int64", + "type": "integer" + } + }, + "title": "VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT.", + "type": "object" + }, + "verifiableCredentialResponse": { + "properties": { + "credential_draft_00": { + "type": "string" + }, + "format": { + "type": "string" + } + }, + "title": "VerifiableCredentialResponse contains the verifiable credential.", + "type": "object" + }, "version": { "properties": { "version": { @@ -3164,6 +3303,58 @@ ] } }, + "/credentials": { + "post": { + "description": "This endpoint creates a verifiable credential that attests that the user\nauthenticated with the provided access token owns a certain public/private key\npair.\n\nMore information can be found at\nhttps://openid.net/specs/openid-connect-userinfo-vc-1_0.html.", + "operationId": "createVerifiableCredential", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVerifiableCredentialRequestBody" + } + } + }, + "x-originalParamName": "Body" + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/verifiableCredentialResponse" + } + } + }, + "description": "verifiableCredentialResponse" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/verifiableCredentialPrimingResponse" + } + } + }, + "description": "verifiableCredentialPrimingResponse" + }, + "default": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorOAuth2" + } + } + }, + "description": "errorOAuth2" + } + }, + "summary": "Issues a Verifiable Credential", + "tags": [ + "oidc" + ] + } + }, "/health/alive": { "get": { "description": "This endpoint returns a HTTP 200 status code when Ory Hydra is accepting incoming\nHTTP requests. This status does currently not include checks whether the database connection is working.\n\nIf the service supports TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto` header to be set.\n\nBe aware that if you are running multiple nodes of this service, the health status will never\nrefer to the cluster state, only to a single instance.", diff --git a/spec/swagger.json b/spec/swagger.json index a492e63c9b..48e19616d0 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1585,6 +1585,52 @@ } } }, + "/credentials": { + "post": { + "description": "This endpoint creates a verifiable credential that attests that the user\nauthenticated with the provided access token owns a certain public/private key\npair.\n\nMore information can be found at\nhttps://openid.net/specs/openid-connect-userinfo-vc-1_0.html.", + "consumes": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "oidc" + ], + "summary": "Issues a Verifiable Credential", + "operationId": "createVerifiableCredential", + "parameters": [ + { + "name": "Body", + "in": "body", + "schema": { + "$ref": "#/definitions/CreateVerifiableCredentialRequestBody" + } + } + ], + "responses": { + "200": { + "description": "verifiableCredentialResponse", + "schema": { + "$ref": "#/definitions/verifiableCredentialResponse" + } + }, + "400": { + "description": "verifiableCredentialPrimingResponse", + "schema": { + "$ref": "#/definitions/verifiableCredentialPrimingResponse" + } + }, + "default": { + "description": "errorOAuth2", + "schema": { + "$ref": "#/definitions/errorOAuth2" + } + } + } + } + }, "/health/alive": { "get": { "description": "This endpoint returns a 200 status code when the HTTP server is up running.\nThis status does currently not include checks whether the database connection is working.\n\nIf the service supports TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto` header to be set.\n\nBe aware that if you are running multiple nodes of this service, the health status will never\nrefer to the cluster state, only to a single instance.", @@ -2054,6 +2100,24 @@ } }, "definitions": { + "CreateVerifiableCredentialRequestBody": { + "type": "object", + "title": "CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential.", + "properties": { + "format": { + "type": "string" + }, + "proof": { + "$ref": "#/definitions/VerifiableCredentialProof" + }, + "types": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "DefaultError": {}, "JSONRawMessage": { "type": "object", @@ -2064,6 +2128,28 @@ "type": "string", "title": "NullDuration represents a nullable JSON and SQL compatible time.Duration." }, + "RFC6749ErrorJson": { + "type": "object", + "title": "RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error.", + "properties": { + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "status_code": { + "type": "integer", + "format": "int64" + } + } + }, "StringSliceJSONFormat": { "type": "array", "title": "StringSliceJSONFormat represents []string{} which is encoded to/from JSON for SQL storage.", @@ -2071,6 +2157,18 @@ "type": "string" } }, + "VerifiableCredentialProof": { + "type": "object", + "title": "VerifiableCredentialProof contains the proof of a verifiable credential.", + "properties": { + "jwt": { + "type": "string" + }, + "proof_type": { + "type": "string" + } + } + }, "acceptOAuth2ConsentRequest": { "type": "object", "title": "The request payload used to accept a consent request.", @@ -2177,6 +2275,38 @@ } } }, + "credentialSupportedDraft00": { + "description": "Includes information about the supported verifiable credentials.", + "type": "object", + "title": "Verifiable Credentials Metadata (Draft 00)", + "properties": { + "cryptographic_binding_methods_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported\n\nContains a list of cryptographic binding methods supported for signing the proof.", + "type": "array", + "items": { + "type": "string" + } + }, + "cryptographic_suites_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Suites Supported\n\nContains a list of cryptographic suites methods supported for signing the proof.", + "type": "array", + "items": { + "type": "string" + } + }, + "format": { + "description": "OpenID Connect Verifiable Credentials Format\n\nContains the format that is supported by this authorization server.", + "type": "string" + }, + "types": { + "description": "OpenID Connect Verifiable Credentials Types\n\nContains the types of verifiable credentials supported.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "errorOAuth2": { "description": "Error", "type": "object", @@ -2999,6 +3129,17 @@ "type": "string" } }, + "credentials_endpoint_draft_00": { + "description": "OpenID Connect Verifiable Credentials Endpoint\n\nContains the URL of the Verifiable Credentials Endpoint.", + "type": "string" + }, + "credentials_supported_draft_00": { + "description": "OpenID Connect Verifiable Credentials Supported\n\nJSON array containing a list of the Verifiable Credentials supported by this authorization server.", + "type": "array", + "items": { + "$ref": "#/definitions/credentialSupportedDraft00" + } + }, "end_session_endpoint": { "description": "OpenID Connect End-Session Endpoint\n\nURL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.", "type": "string" @@ -3460,6 +3601,50 @@ "unexpectedError": { "type": "string" }, + "verifiableCredentialPrimingResponse": { + "type": "object", + "title": "VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT.", + "properties": { + "c_nonce": { + "type": "string" + }, + "c_nonce_expires_in": { + "type": "integer", + "format": "int64" + }, + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "format": { + "type": "string" + }, + "status_code": { + "type": "integer", + "format": "int64" + } + } + }, + "verifiableCredentialResponse": { + "type": "object", + "title": "VerifiableCredentialResponse contains the verifiable credential.", + "properties": { + "credential_draft_00": { + "type": "string" + }, + "format": { + "type": "string" + } + } + }, "version": { "type": "object", "properties": { diff --git a/x/fosite_storer.go b/x/fosite_storer.go index 1afec03771..e7de8603f6 100644 --- a/x/fosite_storer.go +++ b/x/fosite_storer.go @@ -12,6 +12,7 @@ import ( "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/handler/pkce" "github.com/ory/fosite/handler/rfc7523" + "github.com/ory/fosite/handler/verifiable" ) type FositeStorer interface { @@ -20,6 +21,7 @@ type FositeStorer interface { openid.OpenIDConnectRequestStorage pkce.PKCERequestStorage rfc7523.RFC7523KeyStorage + verifiable.NonceManager RevokeRefreshToken(ctx context.Context, requestID string) error diff --git a/x/int_to_bytes.go b/x/int_to_bytes.go new file mode 100644 index 0000000000..4cb8c9e8ca --- /dev/null +++ b/x/int_to_bytes.go @@ -0,0 +1,26 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import ( + "encoding/binary" + + "github.com/pkg/errors" +) + +// IntToBytes converts an int64 to a byte slice. It is the inverse of BytesToInt. +func IntToBytes(i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) + + return b +} + +// BytesToInt converts a byte slice to an int64. It is the inverse of IntToBytes. +func BytesToInt(b []byte) (int64, error) { + if len(b) != 8 { + return 0, errors.New("byte slice must be 8 bytes long") + } + return int64(binary.LittleEndian.Uint64(b)), nil +} diff --git a/x/int_to_bytes_test.go b/x/int_to_bytes_test.go new file mode 100644 index 0000000000..c67f54cc5d --- /dev/null +++ b/x/int_to_bytes_test.go @@ -0,0 +1,52 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import ( + "math" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_toBytes_fromBytes(t *testing.T) { + for _, tc := range []struct { + name string + i int64 + }{ + { + name: "zero", + i: 0, + }, + { + name: "positive", + i: 1234567890, + }, + { + name: "negative", + i: -1234567890, + }, + { + name: "now", + i: time.Now().Unix(), + }, + { + name: "max", + i: math.MaxInt64, + }, + { + name: "min", + i: math.MinInt64, + }, + } { + t.Run("case="+tc.name, func(t *testing.T) { + bytes := IntToBytes(tc.i) + i, err := BytesToInt(bytes) + require.NoError(t, err) + assert.Equal(t, tc.i, i) + }) + } +}