From 5f1f64e00884ebb3bedfff03e934cecec8b9e8cc Mon Sep 17 00:00:00 2001 From: aeneasr Date: Sun, 5 Jul 2020 13:10:33 +0200 Subject: [PATCH 1/3] chore: remove unused test stubs --- stub/social.hydra.schema.json | 21 --------------------- stub/test-identity.schema.json | 27 --------------------------- 2 files changed, 48 deletions(-) delete mode 100644 stub/social.hydra.schema.json delete mode 100644 stub/test-identity.schema.json diff --git a/stub/social.hydra.schema.json b/stub/social.hydra.schema.json deleted file mode 100644 index 6035ecb72f01..000000000000 --- a/stub/social.hydra.schema.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$id": "https://example.com/social.hydra.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "sub": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "mappings": { - "identity": [ - "email" - ] - } - } - } - }, - "required": [ - "sub" - ] -} \ No newline at end of file diff --git a/stub/test-identity.schema.json b/stub/test-identity.schema.json deleted file mode 100644 index 176e17970b3a..000000000000 --- a/stub/test-identity.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$id": "https://example.com/person.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Person", - "type": "object", - "properties": { - "foobar": { - "type": "string", - "minLength": 2 - }, - "username": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true - } - } - } - } - }, - "required": [ - "foobar", - "username" - ], - "additionalProperties": false -} \ No newline at end of file From b86f27168d47a8d07c32147287b40364726718d2 Mon Sep 17 00:00:00 2001 From: aeneasr Date: Tue, 7 Jul 2020 13:47:10 +0200 Subject: [PATCH 2/3] refactor: rename identity traits schema to identity schema Closes #531 BREAKING CHANGE: This patch renames the Identity Traits JSON Schema to Identity JSON Schema. The identity payload has changed from ``` { - "traits_schema_url": "...", - "traits_schema_id": "...", + "schema_url": "...", + "schema_id": "...", } ``` Additionally, it is now expected that your Identity JSON Schema includes a "traits" key at the root level. **Before (example)** ``` { "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", "properties": { "email": { "type": "string", "format": "email", "title": "E-Mail", "minLength": 3, "ory.sh/kratos": { "credentials": { "password": { "identifier": true } }, "verification": { "via": "email" }, "recovery": { "via": "email" } } } }, "required": [ "email" ], "additionalProperties": false } ``` **After (example)** ``` { "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", "properties": { "traits": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "title": "E-Mail", "minLength": 3, "ory.sh/kratos": { "credentials": { "password": { "identifier": true } }, "verification": { "via": "email" }, "recovery": { "via": "email" } } } }, "required": [ "email" ], "additionalProperties": false } } } ``` You also need to remove the `traits` key from your ORY Kratos config like this: ``` identity: - traits: - default_schema_url: http://test.kratos.ory.sh/default-identity.schema.json - schemas: - - id: other - url: http://test.kratos.ory.sh/other-identity.schema.json + default_schema_url: http://test.kratos.ory.sh/default-identity.schema.json + schemas: + - id: other + url: http://test.kratos.ory.sh/other-identity.schema.json ``` Do not forget to also update environment variables for the Identity JSON Schema as well if set. --- .schema/api.swagger.json | 16 +- .schema/config.schema.json | 125 +- continuity/manager_test.go | 2 +- continuity/stub/identity.schema.json | 6 - .../kratos/email-password/.kratos.yml | 3 +- .../identity.traits.schema.json | 47 +- .../openid-connect-oidc-oauth2.mdx | 4 +- .../credentials/username-email-password.mdx | 168 +- docs/docs/concepts/identity-data-model.md | 126 +- docs/docs/concepts/index.md | 2 +- .../account-activation-email-verification.mdx | 29 +- .../account-recovery-password-reset.mdx | 29 +- ...n-with-github-google-facebook-linkedin.mdx | 2 +- docs/docs/quickstart.mdx | 2 +- docs/docs/reference/api.md | 6301 ----------------- docs/docs/reference/html-forms.md | 25 +- .../openid-connect-social-sign-in-oauth2.mdx | 51 +- .../username-email-password.mdx | 106 +- .../link-unlink-openid-connect-oauth2.mdx | 4 +- .../user-settings/user-profile-management.mdx | 4 +- .../flows/verify-email-account-activation.mdx | 58 +- driver/configuration/provider_viper.go | 12 +- driver/registry_default_schemas_test.go | 4 +- go.mod | 4 + identity/handler.go | 6 +- identity/handler_test.go | 18 +- identity/identity.go | 12 +- identity/manager_test.go | 2 +- identity/pool.go | 22 +- identity/stub/extension.schema.json | 60 +- identity/stub/identity-2.schema.json | 9 +- identity/stub/identity.schema.json | 23 +- identity/stub/manager.schema.json | 75 +- identity/validator.go | 22 +- identity/validator_test.go | 54 +- internal/.kratos.yaml | 9 +- internal/httpclient/models/identity.go | 28 +- internal/testhelpers/handler_mock.go | 4 +- .../5ff66179-c240-4703-b0d8-494592cefff5.json | 4 +- .../a251ebc2-880c-4f76-a8f3-38e6940eab0e.json | 4 +- .../d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json | 8 + .../194c5b05-0487-4a11-bcbc-f301c9ff9678.json | 4 +- .../21c5f714-3089-49d2-b387-f244d4dd9e00.json | 4 +- .../74fd6c53-7651-453e-90b8-2c5adbf911bb.json | 4 +- .../77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json | 4 +- .../a79bfcf1-68ae-49de-8b23-4f96921b8341.json | 4 +- persistence/sql/migratest/migration_test.go | 13 +- .../sql/migratest/stub/default.schema.json | 6 + .../testdata/20200705105359_testdata.sql | 1 + ...ename_identities_schema.cockroach.down.sql | 1 + ..._rename_identities_schema.cockroach.up.sql | 1 + ...59_rename_identities_schema.mysql.down.sql | 1 + ...5359_rename_identities_schema.mysql.up.sql | 1 + ...rename_identities_schema.postgres.down.sql | 1 + ...9_rename_identities_schema.postgres.up.sql | 1 + ..._rename_identities_schema.sqlite3.down.sql | 10 + ...59_rename_identities_schema.sqlite3.up.sql | 10 + ...5105359_rename_identities_schema.down.fizz | 1 + ...705105359_rename_identities_schema.up.fizz | 1 + persistence/sql/persister.go | 37 +- persistence/sql/persister_hmac_test.go | 5 +- persistence/sql/persister_identity.go | 10 +- persistence/sql/persister_test.go | 2 +- persistence/sql/stub/identity-2.schema.json | 9 +- persistence/sql/stub/identity.schema.json | 23 +- schema/handler_test.go | 4 +- schema/schema_test.go | 5 +- schema/stub/complex.schema.json | 35 + selfservice/flow/login/handler_test.go | 2 +- selfservice/flow/login/hook_test.go | 2 +- .../flow/login/stub/fake-session.schema.json | 6 +- selfservice/flow/login/stub/login.schema.json | 9 +- .../flow/login/stub/registration.schema.json | 9 +- .../flow/login/stub/updated.schema.json | 9 +- selfservice/flow/logout/handler_test.go | 2 +- .../flow/logout/stub/registration.schema.json | 9 +- selfservice/flow/recovery/handler_test.go | 4 +- selfservice/flow/recovery/persistence.go | 2 +- .../flow/recovery/stub/identity.schema.json | 59 +- selfservice/flow/registration/handler_test.go | 4 +- selfservice/flow/registration/hook_test.go | 2 +- .../stub/fake-session.schema.json | 6 +- .../registration/stub/identity.schema.json | 56 +- .../flow/registration/stub/login.schema.json | 10 +- .../stub/registration.schema.json | 9 +- .../registration/stub/updated.schema.json | 9 +- selfservice/flow/settings/extension.go | 58 - selfservice/flow/settings/extension_test.go | 45 - selfservice/flow/settings/handler_test.go | 2 +- selfservice/flow/settings/hook_test.go | 2 +- selfservice/flow/settings/persistence.go | 4 +- .../flow/settings/stub/identity.schema.json | 55 +- selfservice/flow/verify/handler_test.go | 2 +- selfservice/flow/verify/persistence.go | 2 +- selfservice/flow/verify/sender_test.go | 2 +- .../flow/verify/stub/extension/schema.json | 37 +- selfservice/form/container.go | 2 +- selfservice/form/fields.go | 5 +- selfservice/form/fields_test.go | 2 +- selfservice/form/html_form.go | 4 +- selfservice/form/html_form_test.go | 21 + selfservice/form/stub/identity.schema.json | 43 + selfservice/hook/session_destroyer_test.go | 2 +- selfservice/hook/session_issuer_test.go | 2 +- selfservice/hook/stub/stub.schema.json | 9 +- selfservice/hook/stub/verify.schema.json | 19 +- selfservice/hook/verification_test.go | 2 +- selfservice/strategy/oidc/form.go | 2 +- selfservice/strategy/oidc/strategy.go | 2 +- .../strategy/oidc/strategy_settings_test.go | 14 +- selfservice/strategy/oidc/strategy_test.go | 2 +- .../strategy/oidc/stub/extension/schema.json | 65 +- .../strategy/oidc/stub/form-merge.schema.json | 0 .../strategy/oidc/stub/merge/1.schema.json | 29 +- .../oidc/stub/registration.schema.json | 38 +- .../strategy/oidc/stub/settings.schema.json | 35 +- selfservice/strategy/password/login_test.go | 2 +- selfservice/strategy/password/registration.go | 8 +- .../strategy/password/registration_test.go | 16 +- .../strategy/password/settings_test.go | 14 +- .../strategy/password/stub/login.schema.json | 9 +- .../stub/missing-identifier.schema.json | 27 +- .../password/stub/profile.schema.json | 5 + .../password/stub/registration.schema.json | 37 +- selfservice/strategy/profile/strategy.go | 14 +- selfservice/strategy/profile/strategy_test.go | 12 +- .../profile/stub/identity.schema.json | 55 +- .../recoverytoken/persister_conformity.go | 2 +- .../strategy/recoverytoken/strategy_test.go | 6 +- .../recoverytoken/stub/default.schema.json | 29 +- selfservice/stub/identity.schema.json | 24 +- selfservice/stub/new-form.json | 21 +- selfservice/stub/registration.schema.json | 9 +- selfservice/stub/updated.schema.json | 9 +- session/persistence.go | 6 +- .../profiles/email/login/success.spec.js | 4 +- .../email/registration/success.spec.js | 4 +- .../oidc/registration/success.spec.js | 4 +- test/e2e/profiles/email/.kratos.yml | 3 +- .../email/identity.traits.schema.json | 47 +- test/e2e/profiles/oidc/.kratos.yml | 3 +- .../profiles/oidc/identity.traits.schema.json | 47 +- test/e2e/profiles/recovery/.kratos.yml | 3 +- .../recovery/identity.traits.schema.json | 41 +- test/e2e/profiles/verification/.kratos.yml | 3 +- .../verification/identity.traits.schema.json | 41 +- test/stub/identity/empty.schema.json | 10 + 147 files changed, 1484 insertions(+), 7435 deletions(-) delete mode 100644 continuity/stub/identity.schema.json delete mode 100644 docs/docs/reference/api.md create mode 100644 persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json create mode 100644 persistence/sql/migratest/testdata/20200705105359_testdata.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.down.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.up.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.down.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.down.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.up.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.down.sql create mode 100644 persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.up.sql create mode 100644 persistence/sql/migrations/templates/20200705105359_rename_identities_schema.down.fizz create mode 100644 persistence/sql/migrations/templates/20200705105359_rename_identities_schema.up.fizz delete mode 100644 selfservice/flow/settings/extension.go delete mode 100644 selfservice/flow/settings/extension_test.go create mode 100644 selfservice/form/stub/identity.schema.json delete mode 100644 selfservice/strategy/oidc/stub/form-merge.schema.json create mode 100644 test/stub/identity/empty.schema.json diff --git a/.schema/api.swagger.json b/.schema/api.swagger.json index 935d4de97d87..db3ddfa85785 100755 --- a/.schema/api.swagger.json +++ b/.schema/api.swagger.json @@ -1160,7 +1160,7 @@ "type": "object", "required": [ "id", - "traits_schema_id", + "schema_id", "traits" ], "properties": { @@ -1174,17 +1174,17 @@ "$ref": "#/definitions/RecoveryAddress" } }, - "traits": { - "$ref": "#/definitions/Traits" - }, - "traits_schema_id": { - "description": "TraitsSchemaID is the ID of the JSON Schema to be used for validating the identity's traits.", + "schema_id": { + "description": "SchemaID is the ID of the JSON Schema to be used for validating the identity's traits.", "type": "string" }, - "traits_schema_url": { - "description": "TraitsSchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from.\n\nformat: url", + "schema_url": { + "description": "SchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from.\n\nformat: url", "type": "string" }, + "traits": { + "$ref": "#/definitions/Traits" + }, "verifiable_addresses": { "description": "VerifiableAddresses contains all the addresses that can be verified by the user.", "type": "array", diff --git a/.schema/config.schema.json b/.schema/config.schema.json index 1fa491098607..3306b3babf58 100644 --- a/.schema/config.schema.json +++ b/.schema/config.schema.json @@ -702,79 +702,70 @@ "identity": { "type": "object", "properties": { - "traits": { - "type": "object", - "properties": { - "default_schema_url": { - "title": "JSON Schema URL for default identity traits", - "description": "Path to the JSON Schema which describes a default identity's traits.", - "type": "string", - "format": "uri", - "examples": [ - "file://path/to/identity.traits.schema.json", - "httpss://foo.bar.com/path/to/identity.traits.schema.json" - ] - }, - "schemas": { - "type": "array", - "title": "Additional JSON Schemas for Identity Traits", - "examples": [ - [ - { - "id": "customer", - "url": "https://foo.bar.com/path/to/customer.traits.schema.json" - }, - { - "id": "employee", - "url": "https://foo.bar.com/path/to/employee.traits.schema.json" - }, - { - "id": "employee-v2", - "url": "https://foo.bar.com/path/to/employee.v2.traits.schema.json" - } + "default_schema_url": { + "title": "JSON Schema URL for default identity traits", + "description": "Path to the JSON Schema which describes a default identity's traits.", + "type": "string", + "format": "uri", + "examples": [ + "file://path/to/identity.traits.schema.json", + "httpss://foo.bar.com/path/to/identity.traits.schema.json" + ] + }, + "schemas": { + "type": "array", + "title": "Additional JSON Schemas for Identity Traits", + "examples": [ + [ + { + "id": "customer", + "url": "https://foo.bar.com/path/to/customer.traits.schema.json" + }, + { + "id": "employee", + "url": "https://foo.bar.com/path/to/employee.traits.schema.json" + }, + { + "id": "employee-v2", + "url": "https://foo.bar.com/path/to/employee.v2.traits.schema.json" + } + ] + ], + "items": { + "type": "object", + "properties": { + "id": { + "title": "The schema's ID.", + "type": "string", + "examples": [ + "employee" + ] + }, + "url": { + "type": "string", + "title": "Path to the JSON Schema", + "format": "uri", + "examples": [ + "file://path/to/identity.traits.schema.json", + "https://foo.bar.com/path/to/identity.traits.schema.json" ] - ], - "items": { - "type": "object", - "properties": { - "id": { - "title": "The schema's ID.", - "type": "string", - "examples": [ - "employee" - ] - }, - "url": { - "type": "string", - "title": "Path to the JSON Schema", - "format": "uri", - "examples": [ - "file://path/to/identity.traits.schema.json", - "https://foo.bar.com/path/to/identity.traits.schema.json" - ] - } - }, - "not": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^default$" - } - }, - "additionalProperties": true - } } + }, + "not": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^default$" + } + }, + "additionalProperties": true } - }, - "required": [ - "default_schema_url" - ], - "additionalProperties": false + } } }, "required": [ - "traits" + "default_schema_url" ], "additionalProperties": false }, diff --git a/continuity/manager_test.go b/continuity/manager_test.go index b128d51a6f8a..1751552ae549 100644 --- a/continuity/manager_test.go +++ b/continuity/manager_test.go @@ -39,7 +39,7 @@ type persisterTestPayload struct { func TestManager(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://../test/stub/identity/empty.schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh") i := identity.NewIdentity("") require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) diff --git a/continuity/stub/identity.schema.json b/continuity/stub/identity.schema.json deleted file mode 100644 index fc2f5f5f9764..000000000000 --- a/continuity/stub/identity.schema.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$id": "https://example.com/registration.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": {} -} diff --git a/contrib/quickstart/kratos/email-password/.kratos.yml b/contrib/quickstart/kratos/email-password/.kratos.yml index 00fd53d843ca..f545fe3f3cda 100644 --- a/contrib/quickstart/kratos/email-password/.kratos.yml +++ b/contrib/quickstart/kratos/email-password/.kratos.yml @@ -64,8 +64,7 @@ hashers: key_length: 16 identity: - traits: - default_schema_url: file:///etc/config/kratos/identity.traits.schema.json + default_schema_url: file:///etc/config/kratos/identity.traits.schema.json courier: smtp: diff --git a/contrib/quickstart/kratos/email-password/identity.traits.schema.json b/contrib/quickstart/kratos/email-password/identity.traits.schema.json index d9462aa4f1fe..c87b65cb073b 100644 --- a/contrib/quickstart/kratos/email-password/identity.traits.schema.json +++ b/contrib/quickstart/kratos/email-password/identity.traits.schema.json @@ -4,28 +4,33 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } } - }, - "verification": { - "via": "email" - }, - "recovery": { - "via": "email" } - } + }, + "required": [ + "email" + ], + "additionalProperties": false } - }, - "required": [ - "email" - ], - "additionalProperties": false + } } diff --git a/docs/docs/concepts/credentials/openid-connect-oidc-oauth2.mdx b/docs/docs/concepts/credentials/openid-connect-oidc-oauth2.mdx index 7b95db442721..58e84525be92 100644 --- a/docs/docs/concepts/credentials/openid-connect-oidc-oauth2.mdx +++ b/docs/docs/concepts/credentials/openid-connect-oidc-oauth2.mdx @@ -12,7 +12,7 @@ provider (for example [ORY Hydra](https://www.ory.sh/hydra)). "Social Sign In" or "Sign in with ..." are common aliases for this flow. This strategy expects that you've set up your -[Identity Traits Default JSON Schema](../identity-user-model). +[Default Identity JSON Schema](../identity-user-model). ## Configuration @@ -219,7 +219,7 @@ credentials: - provider: example identifier: some-identity-id-4hA8gk -traits_schema_url: http://foo.bar.com/person.schema.json # This comes from the default identity schema url. +schema_url: http://foo.bar.com/person.schema.json # This comes from the default identity schema url. traits: email: foo@ory.sh # This is extracted from `username` using diff --git a/docs/docs/concepts/credentials/username-email-password.mdx b/docs/docs/concepts/credentials/username-email-password.mdx index 8fb96d4278c7..cbac1935bf40 100644 --- a/docs/docs/concepts/credentials/username-email-password.mdx +++ b/docs/docs/concepts/credentials/username-email-password.mdx @@ -38,16 +38,16 @@ hashers: key_length: 32 ``` -When a user signs up using this strategy, the Default Identity Traits Schema -(set using `identity.traits.default_schema_url`) is used: +When a user signs up using this strategy, the Default Identity JSON Schema +(set using `identity.default_schema_url`) is used: ```yaml title="path/to/my/kratos/config.yml" identity: - traits: - default_schema_url: file:///path/to/default-identity.schema.json - # also works with HTTP(S): - # - # default_schema_url: https://mydomain.com/path/to/default-identity.schema.json + default_schema_url: file:///path/to/default-identity.schema.json + + # also works with HTTP(S): + # + # default_schema_url: https://mydomain.com/path/to/default-identity.schema.json ``` If you don't know what that means, please read the @@ -116,7 +116,7 @@ special meaning for some E-Mail Providers (e.g. GMail) are not normalized: You need to decide which route you want to take. -### Picking the right JSON Schema +### Picking the right Identity JSON Schema When processing an identity and its traits, the method will use [JSON Schema](../../reference/json-schema-json-paths) to extract one or more @@ -125,7 +125,7 @@ identifiers. #### Use Case: Email and Password To use the email address as the login identifier, define the following Identity -Traits Schema: +JSON Schema: ```json { @@ -134,13 +134,18 @@ Traits Schema: "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } @@ -161,15 +166,20 @@ those for log in: "title": "Person", "type": "object", "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } @@ -181,8 +191,7 @@ those for log in: #### Use Case: Username and Password -To use a username as the login identifier, define the following Identity Traits -Schema: +To use a username as the login identifier, define the following Identity JSON Schema: ```json { @@ -191,12 +200,17 @@ Schema: "title": "Person", "type": "object", "properties": { - "username": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "username": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } @@ -216,23 +230,28 @@ You may also mix usernames and passwords: "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } - } - } - }, - "username": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + }, + "username": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } @@ -248,7 +267,7 @@ You may also mix usernames and passwords: ## Example -Assuming your traits schema is as follows: +Assuming your Identity JSON Schema is as follows: ```json { @@ -257,32 +276,37 @@ Assuming your traits schema is as follows: "title": "Person", "type": "object", "properties": { - "first_name": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "first_name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } - } - } - }, - "username": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + }, + "username": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } - } + }, + "additionalProperties": false } - }, - "additionalProperties": false + } } ``` diff --git a/docs/docs/concepts/identity-data-model.md b/docs/docs/concepts/identity-data-model.md index 95886477530b..285eca05af1b 100644 --- a/docs/docs/concepts/identity-data-model.md +++ b/docs/docs/concepts/identity-data-model.md @@ -44,7 +44,7 @@ credentials: # `default` is a special keyword to set this to the schema set by # `default_schema_url`, but it can be any another schema as well. # e.g. customer, employee, employee-v2 -traits_schema_id: default +schema_id: default # Traits represent information about the identity, such as the first or last name. The traits content is completely # up to you and will be validated using the JSON Schema at `traits_schema_url`. @@ -65,13 +65,14 @@ according to your application's needs. They are also supposed to be modified by the identity itself e.g. as part of the registration or profile update process as well as anyone having access to ORY Krato's Admin API. -To validate traits Ory Kratos uses -[JSON Schema](https://json-schema.org/learn/getting-started-step-by-step.html) -adding a small extension "Vocabulary" that allows you to tell ORY Kratos that a +ORY Kratos uses [JSON Schema](https://json-schema.org/learn/getting-started-step-by-step.html) +to validate Identity Traits. + +ORY Kratos defines JSON Schema extension "Vocabulary" that allows you to tell ORY Kratos that a specific trait adds some specific meaning to the standard JSON Schema (more on that later). -Each identity can, theoretically, have a different Traits Schema. This is useful +Each identity can, theoretically, have a different JSON Schema. This is useful in the following situations: - there is more than one type of identity in the system for instance customers, @@ -97,22 +98,21 @@ ORY Kratos expects the JSON Schemas in its configuration file: ```yaml identity: - traits: - # This will be the default JSON Schema. If `traits_schema_id` is empty when creating an identity using the - # Admin API, or a user signs up using a selfservice flow, this schema will be used. - # - # This is a required configuration field! - default_schema_url: http://foo.bar.com/person.schema.json - - # Optionally define additional schemas here: - schemas: - # When creating an identity that uses this schema, `traits_schema_id: customer` would be set for that identity. - - id: customer - url: http://foo.bar.com/customer.schema.json + # This will be the default JSON Schema. If `schema_id` is empty when creating an identity using the + # Admin API, or a user signs up using a selfservice flow, this schema will be used. + # + # This is a required configuration field! + default_schema_url: http://foo.bar.com/person.schema.json + + # Optionally define additional schemas here: + schemas: + # When creating an identity that uses this schema, `traits_schema_id: customer` would be set for that identity. + - id: customer + url: http://foo.bar.com/customer.schema.json ``` -ORY Kratos validates the traits against the corresponding schema on all writing -operations like create or update. The employed business logic must be able to +ORY Kratos validates the Identity Traits against the corresponding schema on all writing +operations (create / update). The employed business logic must be able to distinguish these three types of identities. You might use a switch statement like in the following example: @@ -120,7 +120,7 @@ like in the following example: // This is an example program that can deal with all three types of identities session, err := ory.SessionFromRequest(r) // some error handling -switch (session.Identity.TraitsSchemaID) { +switch (session.Identity.SchemaID) { case "customer": // ... case "employee": @@ -151,17 +151,22 @@ ORY Kratos' JSON Schema Vocabulary Extension can be used within a property: title: 'A customer (v2)', type: 'object', properties: { - email: { - title: 'E-Mail', - type: 'string', - format: 'email', - - // This tells ORY Kratos that the field should be used as the "username" for the username+password flow. - // It is an extension to the regular JSON Schema vocabulary. - 'ory.sh/kratos': { - credentials: { - password: { - identifier: true + traits: { + type: 'object', + properties: { + email: { + title: 'E-Mail', + type: 'string', + format: 'email', + + // This tells ORY Kratos that the field should be used as the "username" for the username+password flow. + // It is an extension to the regular JSON Schema vocabulary. + 'ory.sh/kratos': { + credentials: { + password: { + identifier: true + } + } } } } @@ -213,40 +218,45 @@ password flow title: 'A customer (v2)', type: 'object', properties: { - email: { - title: 'E-Mail', - type: 'string', - format: 'email', - - // This tells ORY Kratos that the field should be used as the "username" for the Username and Password Flow. - 'ory.sh/kratos': { - credentials: { - password: { - identifier: true - } - } - } - }, - name: { + traits: { type: 'object', properties: { - first: { + email: { + title: 'E-Mail', + type: 'string', + format: 'email', + + // This tells ORY Kratos that the field should be used as the "username" for the Username and Password Flow. + 'ory.sh/kratos': { + credentials: { + password: { + identifier: true + } + } + } + }, + name: { + type: 'object', + properties: { + first: { + type: 'string' + }, + last: { + type: 'string' + } + } + }, + favorite_animal: { type: 'string' }, - last: { + accepted_tos: { type: 'string' } - } - }, - favorite_animal: { - type: 'string' - }, - accepted_tos: { - type: 'string' + }, + required: ['email'], + additionalProperties: false } - }, - required: ['email'], - additionalProperties: false + } } ``` diff --git a/docs/docs/concepts/index.md b/docs/docs/concepts/index.md index 3ebe548b639c..39187fde4203 100644 --- a/docs/docs/concepts/index.md +++ b/docs/docs/concepts/index.md @@ -262,7 +262,7 @@ system: attached to the profile. ORY Kratos implements both scenarios by using -[JSON Schemas for Identity Traits](./identity-user-model) +[JSON Schemas for Identities](./identity-user-model) ### Forget passport-js, oidc-client, ... diff --git a/docs/docs/guides/account-activation-email-verification.mdx b/docs/docs/guides/account-activation-email-verification.mdx index 0ac7d9d9c7c6..2c494d705b45 100644 --- a/docs/docs/guides/account-activation-email-verification.mdx +++ b/docs/docs/guides/account-activation-email-verification.mdx @@ -4,7 +4,7 @@ title: Setting up Account Activation and E-Mail Verification --- To set up email verification, your -[Identity Schema](../concepts/identity-data-model.md) must have an email in its +[Identity JSON Schema](../concepts/identity-data-model.md) must have an email in its traits and add ```json @@ -26,18 +26,23 @@ to it, for example: "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, -+ "ory.sh/kratos": { -+ "verification": { -+ "via": "email" -+ } -+ } + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, ++ "ory.sh/kratos": { ++ "verification": { ++ "via": "email" ++ } ++ } + } + } } - }, + } } ``` diff --git a/docs/docs/guides/account-recovery-password-reset.mdx b/docs/docs/guides/account-recovery-password-reset.mdx index 9a62b6e44068..396061b0aaa0 100644 --- a/docs/docs/guides/account-recovery-password-reset.mdx +++ b/docs/docs/guides/account-recovery-password-reset.mdx @@ -4,7 +4,7 @@ title: Setting up Account Recovery and Password Reset --- To set up account recovery, your -[Identity Schema](../concepts/identity-data-model.md) must have an email in its +[Identity JSON Schema](../concepts/identity-data-model.md) must have an email in its traits and add ```json @@ -26,18 +26,23 @@ to it, for example: "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, -+ "ory.sh/kratos": { -+ "recovery": { -+ "via": "email" -+ } -+ } + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, ++ "ory.sh/kratos": { ++ "recovery": { ++ "via": "email" ++ } ++ } + } + } } - }, + } } ``` diff --git a/docs/docs/guides/sign-in-with-github-google-facebook-linkedin.mdx b/docs/docs/guides/sign-in-with-github-google-facebook-linkedin.mdx index a4e53e2022a1..4ecabfca2724 100644 --- a/docs/docs/guides/sign-in-with-github-google-facebook-linkedin.mdx +++ b/docs/docs/guides/sign-in-with-github-google-facebook-linkedin.mdx @@ -54,7 +54,7 @@ As explained in [OpenID Connect and OAuth2 Credentials](../concepts/credentials/openid-connect-oidc-oauth2.mdx), you must also create a Jsonnet code snippet for the provider. Save the code in `/contrib/quickstart/kratos/email-password/oidc.github.jsonnet`. -The following schema takes `email_primary` and maps it to `traits.email`: +The following JsonNet takes `email_primary` and maps it to `traits.email`: ```json title="contrib/quickstart/kratos/email-password/oidc.github.jsonnet" local claims = { diff --git a/docs/docs/quickstart.mdx b/docs/docs/quickstart.mdx index d7b44829d429..bc90a79aca48 100644 --- a/docs/docs/quickstart.mdx +++ b/docs/docs/quickstart.mdx @@ -591,7 +591,7 @@ chapters of this documentation. To get a minimal version of ORY Kratos running, you need to set configuration values for -[`identity.traits.default_schema_url`](https://github.com/ory/kratos/blob/v0.3.0-alpha.1/contrib/quickstart/kratos/email-password/.kratos.yml#L67) +[`identity.default_schema_url`](https://github.com/ory/kratos/blob/v0.3.0-alpha.1/contrib/quickstart/kratos/email-password/.kratos.yml#L67) and [`DSN`](https://github.com/ory/kratos/blob/v0.3.0-alpha.1/quickstart.yml#L42). You should also configure diff --git a/docs/docs/reference/api.md b/docs/docs/reference/api.md deleted file mode 100644 index 19add2afe9fe..000000000000 --- a/docs/docs/reference/api.md +++ /dev/null @@ -1,6301 +0,0 @@ ---- -title: REST API -id: api ---- - -Welcome to the ORY Kratos HTTP API documentation! - -> You are viewing REST API documentation. This documentation is auto-generated -> from a swagger specification which itself is generated from annotations in the -> source code of the project. It is possible that this documentation includes -> bugs and that code samples are incomplete or wrong. -> -> If you find issues in the respective documentation, please do not edit the -> Markdown files directly (as they are generated) but raise an issue on the -> project's GitHub presence instead. This documentation will improve over time -> with your help! If you have ideas how to improve this part of the -> documentation, feel free to share them in a -> [GitHub issue](https://github.com/ory/docs/issues/new) any time. - - - -## health - - - -### Check alive status - -``` -GET /health/alive HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns a 200 status code when the HTTP server is up running. This -status does currently not include checks whether the database connection is -working. - -If the service supports TLS Edge Termination, this endpoint does not require the -`X-Forwarded-Proto` header to be set. - -Be aware that if you are running multiple nodes of this service, the health -status will never refer to the cluster state, only to a single instance. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | healthStatus | [healthStatus](#schemahealthstatus) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "status": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /health/alive \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/health/alive", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/health/alive', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/health/alive"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/health/alive', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/health/alive', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Check readiness status - -``` -GET /health/ready HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns a 200 status code when the HTTP server is up running and -the environment dependencies (e.g. the database) are responsive as well. - -If the service supports TLS Edge Termination, this endpoint does not require the -`X-Forwarded-Proto` header to be set. - -Be aware that if you are running multiple nodes of this service, the health -status will never refer to the cluster state, only to a single instance. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------------------------ | -------------------- | --------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | healthStatus | [healthStatus](#schemahealthstatus) | -| 503 | [Service Unavailable](https://tools.ietf.org/html/rfc7231#section-6.6.4) | healthNotReadyStatus | [healthNotReadyStatus](#schemahealthnotreadystatus) | - -##### Examples - -###### 200 response - -```json -{ - "status": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /health/ready \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/health/ready", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/health/ready', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/health/ready"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/health/ready', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/health/ready', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -## Administrative Endpoints - - - -### List all identities in the system - -``` -GET /identities HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns a login request's context with, for example, error details -and other information. - -Learn how identities work in -[ORY Kratos' User And Identity Model Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | --------------------- | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | A list of identities. | Inline | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - - - -##### Response Schema - -Status Code **200** - -| Name | Type | Required | Restrictions | Description | -| ------------------- | ----------------------------------------------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------- | -| _anonymous_ | [[Identity](#schemaidentity)] | false | none | none | -| » addresses | [[VerifiableAddress](#schemaverifiableaddress)] | false | none | none | -| »» expires_at | string(date-time) | true | none | none | -| »» id | [UUID](#schemauuid)(uuid4) | true | none | none | -| »» value | string | true | none | none | -| »» verified | boolean | true | none | none | -| »» verified_at | string(date-time) | false | none | none | -| »» via | [VerifiableAddressType](#schemaverifiableaddresstype) | true | none | none | -| » id | [UUID](#schemauuid)(uuid4) | true | none | none | -| » traits | [Traits](#schematraits) | true | none | none | -| » traits_schema_id | string | true | none | TraitsSchemaID is the ID of the JSON Schema to be used for validating the identity's traits. | -| » traits_schema_url | string | false | none | TraitsSchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. format: url | - -##### Examples - -###### 200 response - -```json -[ - { - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" - } -] -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /identities \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/identities", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/identities', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/identities"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/identities', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/identities', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Create an identity - -``` -POST /identities HTTP/1.1 -Content-Type: application/json -Accept: application/json - -``` - -This endpoint creates an identity. It is NOT possible to set an identity's -credentials (password, ...) using this method! A way to achieve that will be -introduced in the future. - -Learn how identities work in -[ORY Kratos' User And Identity Model Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model). - -#### Request body - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | --------------------------- | -------- | ----------- | -| body | body | [Identity](#schemaidentity) | true | none | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------ | ----------------------------------- | -| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | A single identity. | [Identity](#schemaidentity) | -| 400 | [Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 201 response - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X POST /identities \ - -H 'Content-Type: application/json' \ -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Content-Type": []string{"application/json"}, - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("POST", "/identities", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); -const input = '{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -}'; -const headers = { - 'Content-Type': 'application/json', 'Accept': 'application/json' -} - -fetch('/identities', { - method: 'POST', - body: input, - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/identities"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("POST"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' -} - -r = requests.post( - '/identities', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Content-Type' => 'application/json', - 'Accept' => 'application/json' -} - -result = RestClient.post '/identities', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get an identity - -``` -GET /identities/{id} HTTP/1.1 -Accept: application/json - -``` - -Learn how identities work in -[ORY Kratos' User And Identity Model Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | ------ | -------- | ---------------------------------------------------- | -| id | path | string | true | ID must be set to the ID of identity you want to get | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | A single identity. | [Identity](#schemaidentity) | -| 400 | [Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /identities/{id} \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/identities/{id}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/identities/{id}', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/identities/{id}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/identities/{id}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/identities/{id}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Update an identity - -``` -PUT /identities/{id} HTTP/1.1 -Content-Type: application/json -Accept: application/json - -``` - -This endpoint updates an identity. It is NOT possible to set an identity's -credentials (password, ...) using this method! A way to achieve that will be -introduced in the future. - -The full identity payload (except credentials) is expected. This endpoint does -not support patching. - -Learn how identities work in -[ORY Kratos' User And Identity Model Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model). - -#### Request body - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | --------------------------- | -------- | ------------------------------------------------------- | -| id | path | string | true | ID must be set to the ID of identity you want to update | -| body | body | [Identity](#schemaidentity) | true | none | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | A single identity. | [Identity](#schemaidentity) | -| 400 | [Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X PUT /identities/{id} \ - -H 'Content-Type: application/json' \ -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Content-Type": []string{"application/json"}, - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("PUT", "/identities/{id}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); -const input = '{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -}'; -const headers = { - 'Content-Type': 'application/json', 'Accept': 'application/json' -} - -fetch('/identities/{id}', { - method: 'PUT', - body: input, - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/identities/{id}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("PUT"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' -} - -r = requests.put( - '/identities/{id}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Content-Type' => 'application/json', - 'Accept' => 'application/json' -} - -result = RestClient.put '/identities/{id}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Delete an identity - -``` -DELETE /identities/{id} HTTP/1.1 -Accept: application/json - -``` - -This endpoint deletes an identity. This can not be undone. - -Learn how identities work in -[ORY Kratos' User And Identity Model Documentation](https://www.ory.sh/docs/next/kratos/concepts/identity-user-model). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | ------ | -------- | ------------------------ | -| id | path | string | true | ID is the identity's ID. | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 404 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X DELETE /identities/{id} \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("DELETE", "/identities/{id}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/identities/{id}', { - method: 'DELETE', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/identities/{id}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("DELETE"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.delete( - '/identities/{id}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.delete '/identities/{id}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -## common - - - -### getSchema - -``` -GET /schemas/{id} HTTP/1.1 -Accept: application/json - -``` - -Get a traits schema definition - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | ------ | -------- | -------------------------------------------------- | -| id | path | string | true | ID must be set to the ID of schema you want to get | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | The raw identity traits schema | Inline | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - - - -##### Response Schema - -##### Examples - -###### 200 response - -```json -{} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /schemas/{id} \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/schemas/{id}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/schemas/{id}', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/schemas/{id}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/schemas/{id}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/schemas/{id}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get the request context of browser-based login user flows - -``` -GET /self-service/browser/flows/requests/login?request=string HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns a login request's context with, for example, error details -and other information. - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies -are set as they are required for CSRF to work. To prevent token scanning -attacks, the public endpoint does not return 404 status codes to prevent -scanning attacks. - -More information can be found at -[ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ------ | -------- | ------------------------------- | -| request | query | string | true | Request is the Login Request ID | - -##### Detailed descriptions - -**request**: Request is the Login Request ID - -The value for this parameter comes from `request` URL Query parameter sent to -your application (e.g. `/login?request=abcde`). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | loginRequest | [loginRequest](#schemaloginrequest) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 410 | [Gone](https://tools.ietf.org/html/rfc7231#section-6.5.9) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "forced": true, - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - } - }, - "request_url": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/requests/login?request=string \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/requests/login", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/requests/login?request=string', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/requests/login?request=string"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/requests/login', - params={ - 'request': 'string'}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/requests/login', - params: { - 'request' => 'string'}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get the request context of browser-based registration user flows - -``` -GET /self-service/browser/flows/requests/registration?request=string HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns a registration request's context with, for example, error -details and other information. - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies -are set as they are required for CSRF to work. To prevent token scanning -attacks, the public endpoint does not return 404 status codes to prevent -scanning attacks. - -More information can be found at -[ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ------ | -------- | -------------------------------------- | -| request | query | string | true | Request is the Registration Request ID | - -##### Detailed descriptions - -**request**: Request is the Registration Request ID - -The value for this parameter comes from `request` URL Query parameter sent to -your application (e.g. `/registration?request=abcde`). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------- | ------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | registrationRequest | [registrationRequest](#schemaregistrationrequest) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 410 | [Gone](https://tools.ietf.org/html/rfc7231#section-6.5.9) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - } - }, - "request_url": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/requests/registration?request=string \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/requests/registration", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/requests/registration?request=string', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/requests/registration?request=string"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/requests/registration', - params={ - 'request': 'string'}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/requests/registration', - params: { - 'request' => 'string'}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get the request context of browser-based settings flows - -``` -GET /self-service/browser/flows/requests/settings?request=string HTTP/1.1 -Accept: application/json - -``` - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies -are set as they are required for checking the auth session. To prevent scanning -attacks, the public endpoint does not return 404 status codes but instead 403 -or 500. - -More information can be found at -[ORY Kratos User Settings & Profile Management Documentation](../self-service/flows/user-settings). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ------ | -------- | ------------------------------- | -| request | query | string | true | Request is the Login Request ID | - -##### Detailed descriptions - -**request**: Request is the Login Request ID - -The value for this parameter comes from `request` URL Query parameter sent to -your application (e.g. `/login?request=abcde`). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | --------------- | ----------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | settingsRequest | [settingsRequest](#schemasettingsrequest) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 410 | [Gone](https://tools.ietf.org/html/rfc7231#section-6.5.9) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "identity": { - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" - }, - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "method": "string" - } - }, - "request_url": "string", - "update_successful": true -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/requests/settings?request=string \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/requests/settings", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/requests/settings?request=string', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/requests/settings?request=string"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/requests/settings', - params={ - 'request': 'string'}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/requests/settings', - params: { - 'request' => 'string'}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get the request context of browser-based verification flows - -``` -GET /self-service/browser/flows/requests/verification?request=string HTTP/1.1 -Accept: application/json - -``` - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies -are set as they are required for checking the auth session. To prevent scanning -attacks, the public endpoint does not return 404 status codes but instead 403 -or 500. - -More information can be found at -[ORY Kratos Email and Phone Verification Documentation](https://www.ory.sh/docs/kratos/selfservice/flows/verify-email-account-activation). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ------ | -------- | ------------------------- | -| request | query | string | true | Request is the Request ID | - -##### Detailed descriptions - -**request**: Request is the Request ID - -The value for this parameter comes from `request` URL Query parameter sent to -your application (e.g. `/verify?request=abcde`). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------------- | ------------------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | verificationRequest | [verificationRequest](#schemaverificationrequest) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "expires_at": "2020-05-15T13:19:28Z", - "form": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "request_url": "string", - "success": true, - "via": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/requests/verification?request=string \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/requests/verification", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/requests/verification?request=string', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/requests/verification?request=string"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/requests/verification', - params={ - 'request': 'string'}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/requests/verification', - params: { - 'request' => 'string'}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Get user-facing self-service errors - -``` -GET /self-service/errors HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns the error associated with a user-facing self service -errors. - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies -are set as they are required for CSRF to work. To prevent token scanning -attacks, the public endpoint does not return 404 status codes to prevent -scanning attacks. - -More information can be found at -[ORY Kratos User User Facing Error Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-facing-errors). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ------ | -------- | ----------- | -| error | query | string | false | none | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | -------------------------- | --------------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | User-facing error response | [errorContainer](#schemaerrorcontainer) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 404 | [Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "errors": {}, - "id": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/errors \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/errors", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/errors', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/errors"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/errors', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/errors', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -## Public Endpoints - - - -### Initialize browser-based login user flow - -``` -GET /self-service/browser/flows/login HTTP/1.1 -Accept: application/json - -``` - -This endpoint initializes a browser-based user login flow. Once initialized, the -browser will be redirected to `selfservice.flows.login.ui_url` with the request -ID set as a query parameter. If a valid user session exists already, the browser -will be redirected to `urls.default_redirect_url`. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...). - -More information can be found at -[ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/login \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/login", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/login', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/login"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/login', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/login', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Initialize Browser-Based Logout User Flow - -``` -GET /self-service/browser/flows/logout HTTP/1.1 -Accept: application/json - -``` - -This endpoint initializes a logout flow. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...). - -On successful logout, the browser will be redirected (HTTP 302 Found) to -`urls.default_return_to`. - -More information can be found at -[ORY Kratos User Logout Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-logout). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/logout \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/logout", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/logout', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/logout"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/logout', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/logout', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Initialize browser-based registration user flow - -``` -GET /self-service/browser/flows/registration HTTP/1.1 -Accept: application/json - -``` - -This endpoint initializes a browser-based user registration flow. Once -initialized, the browser will be redirected to -`selfservice.flows.registration.ui_url` with the request ID set as a query -parameter. If a valid user session exists already, the browser will be -redirected to `urls.default_redirect_url`. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...). - -More information can be found at -[ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/registration \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/registration", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/registration', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/registration"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/registration', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/registration', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Complete the browser-based settings flow for the OpenID Connect strategy - -``` -POST /self-service/browser/flows/registration/strategies/oidc/settings/connections HTTP/1.1 -Accept: application/json - -``` - -This endpoint completes a browser-based settings flow. This is usually achieved -by POSTing data to this endpoint. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...) and HTML Forms. - -More information can be found at -[ORY Kratos User Settings & Profile Management Documentation](../self-service/flows/user-settings). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X POST /self-service/browser/flows/registration/strategies/oidc/settings/connections \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("POST", "/self-service/browser/flows/registration/strategies/oidc/settings/connections", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/registration/strategies/oidc/settings/connections', { - method: 'POST', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/registration/strategies/oidc/settings/connections"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("POST"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.post( - '/self-service/browser/flows/registration/strategies/oidc/settings/connections', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.post '/self-service/browser/flows/registration/strategies/oidc/settings/connections', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Initialize browser-based settings flow - -``` -GET /self-service/browser/flows/settings HTTP/1.1 -Accept: application/json - -``` - -This endpoint initializes a browser-based settings flow. Once initialized, the -browser will be redirected to `selfservice.flows.settings.ui_url` with the -request ID set as a query parameter. If no valid user session exists, a login -flow will be initialized. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...). - -More information can be found at -[ORY Kratos User Settings & Profile Management Documentation](../self-service/flows/user-settings). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/settings \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/settings", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/settings', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/settings"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/settings', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/settings', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Complete the browser-based settings flow for the password strategy - -``` -POST /self-service/browser/flows/settings/strategies/password HTTP/1.1 -Accept: application/json - -``` - -This endpoint completes a browser-based settings flow. This is usually achieved -by POSTing data to this endpoint. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...) and HTML Forms. - -More information can be found at -[ORY Kratos User Settings & Profile Management Documentation](../self-service/flows/user-settings). - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X POST /self-service/browser/flows/settings/strategies/password \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("POST", "/self-service/browser/flows/settings/strategies/password", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/settings/strategies/password', { - method: 'POST', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/settings/strategies/password"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("POST"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.post( - '/self-service/browser/flows/settings/strategies/password', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.post '/self-service/browser/flows/settings/strategies/password', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Complete the browser-based settings flow for profile data - -``` -POST /self-service/browser/flows/settings/strategies/profile?request=string HTTP/1.1 -Content-Type: application/json -Accept: application/json - -``` - -This endpoint completes a browser-based settings flow. This is usually achieved -by POSTing data to this endpoint. - -If the provided profile data is valid against the Identity's Traits JSON Schema, -the data will be updated and the browser redirected to `url.settings_ui` for -further steps. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...) and HTML Forms. - -More information can be found at -[ORY Kratos User Settings & Profile Management Documentation](../self-service/flows/user-settings). - -#### Request body - -```json -{ - "request_id": "string", - "traits": {} -} -``` - -```yaml -request_id: string -traits: {} -``` - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------- | -| request | query | string | true | Request is the request ID. | -| body | body | [completeSelfServiceBrowserSettingsStrategyProfileFlowPayload](#schemacompleteselfservicebrowsersettingsstrategyprofileflowpayload) | true | none | - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X POST /self-service/browser/flows/settings/strategies/profile?request=string \ - -H 'Content-Type: application/json' \ -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Content-Type": []string{"application/json"}, - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("POST", "/self-service/browser/flows/settings/strategies/profile", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); -const input = '{ - "request_id": "string", - "traits": {} -}'; -const headers = { - 'Content-Type': 'application/json', 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/settings/strategies/profile?request=string', { - method: 'POST', - body: input, - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/settings/strategies/profile?request=string"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("POST"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json' -} - -r = requests.post( - '/self-service/browser/flows/settings/strategies/profile', - params={ - 'request': 'string'}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Content-Type' => 'application/json', - 'Accept' => 'application/json' -} - -result = RestClient.post '/self-service/browser/flows/settings/strategies/profile', - params: { - 'request' => 'string'}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Initialize browser-based verification flow - -``` -GET /self-service/browser/flows/verification/init/{via} HTTP/1.1 -Accept: application/json - -``` - -This endpoint initializes a browser-based verification flow. Once initialized, -the browser will be redirected to `selfservice.flows.settings.ui_url` with the -request ID set as a query parameter. If no valid user session exists, a login -flow will be initialized. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...). - -More information can be found at -[ORY Kratos Email and Phone Verification Documentation](https://www.ory.sh/docs/kratos/selfservice/flows/verify-email-account-activation). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | ------ | -------- | -------------- | -| via | path | string | true | What to verify | - -##### Detailed descriptions - -**via**: What to verify - -Currently only "email" is supported. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/verification/init/{via} \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/verification/init/{via}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/verification/init/{via}', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/verification/init/{via}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/verification/init/{via}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/verification/init/{via}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Complete the browser-based verification flows - -``` -GET /self-service/browser/flows/verification/{via}/confirm/{code} HTTP/1.1 -Accept: application/json - -``` - -This endpoint completes a browser-based verification flow. - -> This endpoint is NOT INTENDED for API clients and only works with browsers -> (Chrome, Firefox, ...) and HTML Forms. - -More information can be found at -[ORY Kratos Email and Phone Verification Documentation](https://www.ory.sh/docs/kratos/selfservice/flows/verify-email-account-activation). - - - -##### Parameters - -| Parameter | In | Type | Required | Description | -| --------- | ---- | ------ | -------- | -------------- | -| code | path | string | true | none | -| via | path | string | true | What to verify | - -##### Detailed descriptions - -**via**: What to verify - -Currently only "email" is supported. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| 302 | [Found](https://tools.ietf.org/html/rfc7231#section-6.4.3) | Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is | -| typically 201. | None | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 500 response - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /self-service/browser/flows/verification/{via}/confirm/{code} \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/self-service/browser/flows/verification/{via}/confirm/{code}", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/self-service/browser/flows/verification/{via}/confirm/{code}', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/self-service/browser/flows/verification/{via}/confirm/{code}"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/self-service/browser/flows/verification/{via}/confirm/{code}', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/self-service/browser/flows/verification/{via}/confirm/{code}', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -### Check who the current HTTP session belongs to - -``` -GET /sessions/whoami HTTP/1.1 -Accept: application/json - -``` - -Uses the HTTP Headers in the GET request to determine (e.g. by using checking -the cookies) who is authenticated. Returns a session object or 401 if the -credentials are invalid or no credentials were sent. - -This endpoint is useful for reverse proxies and API Gateways. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | -------------------------------------------------------------------------- | ------------ | ----------------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | session | [session](#schemasession) | -| 403 | [Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3) | genericError | [genericError](#schemagenericerror) | -| 500 | [Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1) | genericError | [genericError](#schemagenericerror) | - -##### Examples - -###### 200 response - -```json -{ - "authenticated_at": "2020-05-15T13:19:28Z", - "expires_at": "2020-05-15T13:19:28Z", - "identity": { - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" - }, - "issued_at": "2020-05-15T13:19:28Z", - "sid": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /sessions/whoami \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/sessions/whoami", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/sessions/whoami', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/sessions/whoami"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/sessions/whoami', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/sessions/whoami', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- - - -## version - - - -### Get service version - -``` -GET /version HTTP/1.1 -Accept: application/json - -``` - -This endpoint returns the service version typically notated using semantic -versioning. - -If the service supports TLS Edge Termination, this endpoint does not require the -`X-Forwarded-Proto` header to be set. - -Be aware that if you are running multiple nodes of this service, the health -status will never refer to the cluster state, only to a single instance. - -#### Responses - - - -##### Overview - -| Status | Meaning | Description | Schema | -| ------ | ------------------------------------------------------- | ----------- | ------------------------- | -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | version | [version](#schemaversion) | - -##### Examples - -###### 200 response - -```json -{ - "version": "string" -} -``` - - - -#### Code samples - -
- -
-
- -```shell -curl -X GET /version \ - -H 'Accept: application/json' -``` - -
-
- -```go -package main - -import ( - "bytes" - "net/http" -) - -func main() { - headers := map[string][]string{ - "Accept": []string{"application/json"}, - } - - var body []byte - // body = ... - - req, err := http.NewRequest("GET", "/version", bytes.NewBuffer(body)) - req.Header = headers - - client := &http.Client{} - resp, err := client.Do(req) - // ... -} -``` - -
-
- -```nodejs -const fetch = require('node-fetch'); - -const headers = { - 'Accept': 'application/json' -} - -fetch('/version', { - method: 'GET', - headers -}) -.then(r => r.json()) -.then((body) => { - console.log(body) -}) -``` - -
-
- -```java -// This sample needs improvement. -URL obj = new URL("/version"); - -HttpURLConnection con = (HttpURLConnection) obj.openConnection(); -con.setRequestMethod("GET"); - -int responseCode = con.getResponseCode(); - -BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream()) -); - -String inputLine; -StringBuffer response = new StringBuffer(); -while ((inputLine = in.readLine()) != null) { - response.append(inputLine); -} -in.close(); - -System.out.println(response.toString()); -``` - -
-
- -```python -import requests - -headers = { - 'Accept': 'application/json' -} - -r = requests.get( - '/version', - params={}, - headers = headers) - -print r.json() -``` - -
-
- -```ruby -require 'rest-client' -require 'json' - -headers = { - 'Accept' => 'application/json' -} - -result = RestClient.get '/version', - params: {}, headers: headers - -p JSON.parse(result) -``` - -
-
-
- -## Schemas - -CredentialsType - -#### CredentialsType - - - -```json -"string" -``` - -_CredentialsType represents several different credential types, like password -credentials, passwordless credentials,_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------------------------------------------------------------------------------------------------------------------- | ------ | -------- | ------------ | ----------- | -| CredentialsType represents several different credential types, like password credentials, passwordless credentials, | string | false | none | and so on. | - -Error - -#### Error - - - -```json -{ - "message": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------- | ------ | -------- | ------------ | ---------------------------------------- | -| message | string | false | none | Code FormErrorCode `json:"id,omitempty"` | - -Errors - -#### Errors - - - -```json -[ - { - "message": "string" - } -] -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ----------------------- | -------- | ------------ | ----------- | -| _anonymous_ | [[Error](#schemaerror)] | false | none | none | - -Identity - -#### Identity - - - -```json -{ - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------------- | ----------------------------------------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------- | -| addresses | [[VerifiableAddress](#schemaverifiableaddress)] | false | none | none | -| id | [UUID](#schemauuid) | true | none | none | -| traits | [Traits](#schematraits) | true | none | none | -| traits_schema_id | string | true | none | TraitsSchemaID is the ID of the JSON Schema to be used for validating the identity's traits. | -| traits_schema_url | string | false | none | TraitsSchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. format: url | - -ProviderCredentialsConfig - -#### ProviderCredentialsConfig - - - -```json -{ - "provider": "string", - "subject": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------- | ------ | -------- | ------------ | ----------- | -| provider | string | false | none | none | -| subject | string | false | none | none | - -RequestMethodConfig - -#### RequestMethodConfig - - - -```json -{ - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------- | -| action | string | true | none | Action should be used as the form action URL `
`. | -| errors | [[Error](#schemaerror)] | false | none | Errors contains all form errors. These will be duplicates of the individual field errors. | -| fields | [formFields](#schemaformfields) | true | none | Fields contains multiple fields | -| method | string | true | none | Method is the form method (e.g. POST) | - -Traits - -#### Traits - - - -```json -{} -``` - -#### Properties - -_None_ - -UUID - -#### UUID - - - -```json -"string" -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ------------- | -------- | ------------ | ----------- | -| _anonymous_ | string(uuid4) | false | none | none | - -VerifiableAddress - -#### VerifiableAddress - - - -```json -{ - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ----------------------------------------------------- | -------- | ------------ | ----------- | -| expires_at | string(date-time) | true | none | none | -| id | [UUID](#schemauuid) | true | none | none | -| value | string | true | none | none | -| verified | boolean | true | none | none | -| verified_at | string(date-time) | false | none | none | -| via | [VerifiableAddressType](#schemaverifiableaddresstype) | true | none | none | - -VerifiableAddressType - -#### VerifiableAddressType - - - -```json -"string" -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ------ | -------- | ------------ | ----------- | -| _anonymous_ | string | false | none | none | - -completeSelfServiceBrowserSettingsStrategyProfileFlowPayload - -#### completeSelfServiceBrowserSettingsStrategyProfileFlowPayload - - - -```json -{ - "request_id": "string", - "traits": {} -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ---------- | ------ | -------- | ------------ | ------------------------------------------------------------------------- | -| request_id | string | false | none | RequestID is request ID. in: query | -| traits | object | true | none | Traits contains all of the identity's traits. type: string format: binary | - -errorContainer - -#### errorContainer - - - -```json -{ - "errors": {}, - "id": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------------------- | -------- | ------------ | ----------- | -| errors | object | false | none | none | -| id | [UUID](#schemauuid) | false | none | none | - -form - -#### form - - - -```json -{ - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" -} -``` - -_HTMLForm represents a HTML Form. The container can work with both HTTP Form and -JSON requests_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------- | -| action | string | true | none | Action should be used as the form action URL ``. | -| errors | [[Error](#schemaerror)] | false | none | Errors contains all form errors. These will be duplicates of the individual field errors. | -| fields | [formFields](#schemaformfields) | true | none | Fields contains multiple fields | -| method | string | true | none | Method is the form method (e.g. POST) | - -formField - -#### formField - - - -```json -{ - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} -} -``` - -_Field represents a HTML Form Field_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------- | ----------------------- | -------- | ------------ | ---------------------------------------------------------------- | -| disabled | boolean | false | none | Disabled is the equivalent of `` | -| errors | [Errors](#schemaerrors) | false | none | none | -| name | string | true | none | Name is the equivalent of `` | -| pattern | string | false | none | Pattern is the equivalent of `` | -| required | boolean | false | none | Required is the equivalent of `` | -| type | string | true | none | Type is the equivalent of `` | -| value | object | false | none | Value is the equivalent of `` | - -formFields - -#### formFields - - - -```json -[ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } -] -``` - -_Fields contains multiple fields_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ------------------------------- | -------- | ------------ | ------------------------------- | -| _anonymous_ | [[formField](#schemaformfield)] | false | none | Fields contains multiple fields | - -genericError - -#### genericError - - - -```json -{ - "error": { - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" - } -} -``` - -_Error response_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----- | ------------------------------------------------- | -------- | ------------ | ----------- | -| error | [genericErrorPayload](#schemagenericerrorpayload) | false | none | none | - -genericErrorPayload - -#### genericErrorPayload - - - -```json -{ - "code": 404, - "debug": "The database adapter was unable to find the element", - "details": { - "property1": {}, - "property2": {} - }, - "message": "string", - "reason": "string", - "request": "string", - "status": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------------- | -------------- | -------- | ------------ | -------------------------------------------------------------------------------------- | -| code | integer(int64) | false | none | Code represents the error status code (404, 403, 401, ...). | -| debug | string | false | none | Debug contains debug information. This is usually not available and has to be enabled. | -| details | object | false | none | none | -| » **additionalProperties** | object | false | none | none | -| message | string | false | none | none | -| reason | string | false | none | none | -| request | string | false | none | none | -| status | string | false | none | none | - -healthNotReadyStatus - -#### healthNotReadyStatus - - - -```json -{ - "errors": { - "property1": "string", - "property2": "string" - } -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ------ | -------- | ------------ | ------------------------------------------------------------------ | -| errors | object | false | none | Errors contains a list of errors that caused the not ready status. | -| » **additionalProperties** | string | false | none | none | - -healthStatus - -#### healthStatus - - - -```json -{ - "status": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------ | -------- | ------------ | ---------------------------- | -| status | string | false | none | Status always contains "ok". | - -loginRequest - -#### loginRequest - - - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "forced": true, - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - } - }, - "request_url": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ----------------------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| active | [CredentialsType](#schemacredentialstype) | false | none | and so on. | -| expires_at | string(date-time) | true | none | ExpiresAt is the time (UTC) when the request expires. If the user still wishes to log in, a new request has to be initiated. | -| forced | boolean | false | none | Forced stores whether this login request should enforce reauthentication. | -| id | [UUID](#schemauuid) | true | none | none | -| issued_at | string(date-time) | true | none | IssuedAt is the time (UTC) when the request occurred. | -| methods | object | true | none | Methods contains context for all enabled login methods. If a login request has been processed, but for example the password is incorrect, this will contain error messages. | -| » **additionalProperties** | [loginRequestMethod](#schemaloginrequestmethod) | false | none | none | -| request_url | string | true | none | RequestURL is the initial URL that was requested from ORY Kratos. It can be used to forward information contained in the URL's path or query for example. | - -loginRequestMethod - -#### loginRequestMethod - - - -```json -{ - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ----------------------------------------------------------- | -------- | ------------ | ----------- | -| config | [loginRequestMethodConfig](#schemaloginrequestmethodconfig) | true | none | none | -| method | [CredentialsType](#schemacredentialstype) | true | none | and so on. | - -loginRequestMethodConfig - -#### loginRequestMethodConfig - - - -```json -{ - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| --------- | ------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------- | -| action | string | true | none | Action should be used as the form action URL ``. | -| errors | [[Error](#schemaerror)] | false | none | Errors contains all form errors. These will be duplicates of the individual field errors. | -| fields | [formFields](#schemaformfields) | true | none | Fields contains multiple fields | -| method | string | true | none | Method is the form method (e.g. POST) | -| providers | [[formField](#schemaformfield)] | false | none | Providers is set for the "oidc" request method. | - -registrationRequest - -#### registrationRequest - - - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" - } - }, - "request_url": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ------------------------------------------------------------- | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| active | [CredentialsType](#schemacredentialstype) | false | none | and so on. | -| expires_at | string(date-time) | true | none | ExpiresAt is the time (UTC) when the request expires. If the user still wishes to log in, a new request has to be initiated. | -| id | [UUID](#schemauuid) | true | none | none | -| issued_at | string(date-time) | true | none | IssuedAt is the time (UTC) when the request occurred. | -| methods | object | true | none | Methods contains context for all enabled registration methods. If a registration request has been processed, but for example the password is incorrect, this will contain error messages. | -| » **additionalProperties** | [registrationRequestMethod](#schemaregistrationrequestmethod) | false | none | none | -| request_url | string | true | none | RequestURL is the initial URL that was requested from ORY Kratos. It can be used to forward information contained in the URL's path or query for example. | - -registrationRequestMethod - -#### registrationRequestMethod - - - -```json -{ - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] - }, - "method": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------------------------------------------------------------------------- | -------- | ------------ | ----------- | -| config | [registrationRequestMethodConfig](#schemaregistrationrequestmethodconfig) | false | none | none | -| method | [CredentialsType](#schemacredentialstype) | false | none | and so on. | - -registrationRequestMethodConfig - -#### registrationRequestMethodConfig - - - -```json -{ - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string", - "providers": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ] -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| --------- | ------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------- | -| action | string | true | none | Action should be used as the form action URL ``. | -| errors | [[Error](#schemaerror)] | false | none | Errors contains all form errors. These will be duplicates of the individual field errors. | -| fields | [formFields](#schemaformfields) | true | none | Fields contains multiple fields | -| method | string | true | none | Method is the form method (e.g. POST) | -| providers | [[formField](#schemaformfield)] | false | none | Providers is set for the "oidc" request method. | - -session - -#### session - - - -```json -{ - "authenticated_at": "2020-05-15T13:19:28Z", - "expires_at": "2020-05-15T13:19:28Z", - "identity": { - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" - }, - "issued_at": "2020-05-15T13:19:28Z", - "sid": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ---------------- | --------------------------- | -------- | ------------ | ----------- | -| authenticated_at | string(date-time) | true | none | none | -| expires_at | string(date-time) | true | none | none | -| identity | [Identity](#schemaidentity) | true | none | none | -| issued_at | string(date-time) | true | none | none | -| sid | [UUID](#schemauuid) | true | none | none | - -settingsRequest - -#### settingsRequest - - - -```json -{ - "active": "string", - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "identity": { - "addresses": [ - { - "expires_at": "2020-05-15T13:19:28Z", - "id": "string", - "value": "string", - "verified": true, - "verified_at": "2020-05-15T13:19:28Z", - "via": "string" - } - ], - "id": "string", - "traits": {}, - "traits_schema_id": "string", - "traits_schema_url": "string" - }, - "issued_at": "2020-05-15T13:19:28Z", - "methods": { - "property1": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "method": "string" - }, - "property2": { - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "method": "string" - } - }, - "request_url": "string", - "update_successful": true -} -``` - -_Request presents a settings request_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| -------------------------- | ----------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| active | string | false | none | Active, if set, contains the registration method that is being used. It is initially not set. | -| expires_at | string(date-time) | true | none | ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting, a new request has to be initiated. | -| id | [UUID](#schemauuid) | true | none | none | -| identity | [Identity](#schemaidentity) | true | none | none | -| issued_at | string(date-time) | true | none | IssuedAt is the time (UTC) when the request occurred. | -| methods | object | true | none | Methods contains context for all enabled registration methods. If a registration request has been processed, but for example the password is incorrect, this will contain error messages. | -| » **additionalProperties** | [settingsRequestMethod](#schemasettingsrequestmethod) | false | none | none | -| request_url | string | true | none | RequestURL is the initial URL that was requested from ORY Kratos. It can be used to forward information contained in the URL's path or query for example. | -| update_successful | boolean | true | none | UpdateSuccessful, if true, indicates that the settings request has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a request with invalid (e.g. "please use a valid phone number") data was sent. | - -settingsRequestMethod - -#### settingsRequestMethod - - - -```json -{ - "config": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "method": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------ | ------------------------------------------------- | -------- | ------------ | --------------------------------------------- | -| config | [RequestMethodConfig](#schemarequestmethodconfig) | false | none | none | -| method | string | false | none | Method contains the request credentials type. | - -verificationRequest - -#### verificationRequest - - - -```json -{ - "expires_at": "2020-05-15T13:19:28Z", - "form": { - "action": "string", - "errors": [ - { - "message": "string" - } - ], - "fields": [ - { - "disabled": true, - "errors": [ - { - "message": "string" - } - ], - "name": "string", - "pattern": "string", - "required": true, - "type": "string", - "value": {} - } - ], - "method": "string" - }, - "id": "string", - "issued_at": "2020-05-15T13:19:28Z", - "request_url": "string", - "success": true, - "via": "string" -} -``` - -_Request presents a verification request_ - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ----------- | ----------------------------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| expires_at | string(date-time) | false | none | ExpiresAt is the time (UTC) when the request expires. If the user still wishes to verify the address, a new request has to be initiated. | -| form | [form](#schemaform) | false | none | HTMLForm represents a HTML Form. The container can work with both HTTP Form and JSON requests | -| id | [UUID](#schemauuid) | false | none | none | -| issued_at | string(date-time) | false | none | IssuedAt is the time (UTC) when the request occurred. | -| request_url | string | false | none | RequestURL is the initial URL that was requested from ORY Kratos. It can be used to forward information contained in the URL's path or query for example. | -| success | boolean | false | none | Success, if true, implies that the request was completed successfully. | -| via | [VerifiableAddressType](#schemaverifiableaddresstype) | false | none | none | - -version - -#### version - - - -```json -{ - "version": "string" -} -``` - -#### Properties - -| Name | Type | Required | Restrictions | Description | -| ------- | ------ | -------- | ------------ | --------------------------------- | -| version | string | false | none | Version is the service's version. | diff --git a/docs/docs/reference/html-forms.md b/docs/docs/reference/html-forms.md index 83a8c4c14141..9eed9052ce92 100644 --- a/docs/docs/reference/html-forms.md +++ b/docs/docs/reference/html-forms.md @@ -6,26 +6,31 @@ title: HTML Form Parser If you're using HTML Forms to sign users up or update profiles, ORY Kratos needs to assert the type of each field, as HTML Form Field Values are untyped. -ORY Kratos uses the JSON Schema to assert types. There are a few tricks you +ORY Kratos uses the Identity JSON Schema to assert form field types. There are a few tricks you should know when using this feature. ## Nesting -Assuming this JSON Schema: +Assuming this Identity JSON Schema: ```json { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { - "name": { + "traits": { "type": "object", "properties": { - "first": { - "type": "string" - }, - "last": { - "type": "string" + "name": { + "type": "object", + "properties": { + "first": { + "type": "string" + }, + "last": { + "type": "string" + } + } } } } @@ -33,10 +38,10 @@ Assuming this JSON Schema: } ``` -You could address `name.first` this with an HTML Input Form: +You could address `traits.name.first` this with an HTML Input Form: ``` - + ``` ## Checkboxes diff --git a/docs/docs/self-service/flows/user-login-user-registration/openid-connect-social-sign-in-oauth2.mdx b/docs/docs/self-service/flows/user-login-user-registration/openid-connect-social-sign-in-oauth2.mdx index bdffad11c904..ebfeb2df650d 100644 --- a/docs/docs/self-service/flows/user-login-user-registration/openid-connect-social-sign-in-oauth2.mdx +++ b/docs/docs/self-service/flows/user-login-user-registration/openid-connect-social-sign-in-oauth2.mdx @@ -156,40 +156,45 @@ Provider configuration: } ``` -The next step depends on your Identity Traits JSON Schema and your JsonNet code. +The next step depends on your Identity JSON Schema and your JsonNet code. We're using the following in this example: -```jsonnet title="path/to/identity.traits.json.schema +```json title="path/to/identity.traits.json.schema { "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "website": { + "type": "string", + "format": "uri", + "minLength": 10 } - } - }, - "website": { - "type": "string", - "format": "uri", - "minLength": 10 + }, + "required": [ + "email", + "website" + ], + "additionalProperties": false } - }, - "required": [ - "email", - "website" - ], - "additionalProperties": false + } } ``` diff --git a/docs/docs/self-service/flows/user-login-user-registration/username-email-password.mdx b/docs/docs/self-service/flows/user-login-user-registration/username-email-password.mdx index 6407d254752a..4d62e6e2c0a1 100644 --- a/docs/docs/self-service/flows/user-login-user-registration/username-email-password.mdx +++ b/docs/docs/self-service/flows/user-login-user-registration/username-email-password.mdx @@ -26,9 +26,9 @@ Redirecting the browser to the initiates the flow. If the `password` strategy is enabled, the Registration Request Response Payload will include a `password` method. -ORY Kratos uses the JSON Schema defined in `identity.traits.default_schema_url` +ORY Kratos uses the Identity JSON Schema defined in `identity.default_schema_url` to generate a list of form fields and add it to the Registration Request. Using -a JSON Schema like +an Identity JSON Schema like ```json title="my/identity.schema.json" { @@ -37,33 +37,38 @@ a JSON Schema like "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true - } - } - } - }, - "name": { + "traits": { "type": "object", "properties": { - "first": { - "type": "string" + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } + } }, - "last": { - "type": "string" + "name": { + "type": "object", + "properties": { + "first": { + "type": "string" + }, + "last": { + "type": "string" + } + } } - } + }, + "required": ["email"], + "additionalProperties": false } - }, - "required": ["email"], - "additionalProperties": false + } } ``` @@ -127,7 +132,7 @@ which in turn is easily to render by filling out a HTML Form template: ``` Once the user clicks "Create Account", the payload will be sent to ORY Kratos' -Public API. The data will be validated against the JSON Schema (e.g. checking if +Public API. The data will be validated against the Identity JSON Schema (e.g. checking if a required field is missing, if some condition like `minLength` is not fulfilled, ...). If the data is invalid or incomplete, the browser will be redirected to the same login endpoint with the same request ID. When fetching @@ -185,7 +190,7 @@ Redirecting the browser to the [Self-Service Login and Registration Endpoint](../user-login-user-registration.mdx#user-login-and-user-registration-process-sequence) initiates the flow. If the `password` strategy is enabled, the Login Request Response Payload will include a `password` method. In contrast to the -Registration sequence, this payload does not change when the Identity Traits +Registration sequence, this payload does not change when the Identity JSON Schema changes: ```json5 title="$ curl http:///self-service/browser/flows/requests/login?request=0cfb0f7e-3866-453c-9c23-28cc2cb7fead" @@ -399,33 +404,32 @@ Enforcing email verification, which requires an email round trip and disrupts the sign up process, is not always feasible. In these cases, you might want to disable account enumeration defenses. -You can disable the defense mechanism on a per-field basis in your Identity -Traits Schema: +You can disable the defense mechanism on a per-field basis in your Identity JSON Schema: -```json title="path/to/my/identity.traits.schema.json" +```json title="path/to/my/identity.schema.json" { - $id': 'https://example.com/identity.traits.schema.json', - $schema': 'http://json-schema.org/draft-07/schema#', - title': 'Person', - type': 'object', - properties': - { - 'username': - { - 'type': 'string', - 'ory.sh/kratos': - { - 'credentials': - { - 'password': - { - 'identifier': true, - 'disable_account_enumeration_defenses': true, - }, - }, - }, - }, - }, + "$id": "https://example.com/identity.traits.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "username": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true, + "disable_account_enumeration_defenses": true + } + } + } + } + } + } + } } ``` diff --git a/docs/docs/self-service/flows/user-settings/link-unlink-openid-connect-oauth2.mdx b/docs/docs/self-service/flows/user-settings/link-unlink-openid-connect-oauth2.mdx index 8579019f9e02..13524015dbb0 100644 --- a/docs/docs/self-service/flows/user-settings/link-unlink-openid-connect-oauth2.mdx +++ b/docs/docs/self-service/flows/user-settings/link-unlink-openid-connect-oauth2.mdx @@ -110,8 +110,8 @@ enabled, it can not be unlinked and is therefore hidden from the form: }, identity: { id: 'dd8ce04e-c636-4488-bc92-b5debf73fd30', - traits_schema_id: 'default', - traits_schema_url: '', + schema_id: 'default', + schema_url: '', traits: { email: 'superuser@ory.sh', website: 'https://www.ory.sh' diff --git a/docs/docs/self-service/flows/user-settings/user-profile-management.mdx b/docs/docs/self-service/flows/user-settings/user-profile-management.mdx index 5c35a681691e..cc5fb065fefe 100644 --- a/docs/docs/self-service/flows/user-settings/user-profile-management.mdx +++ b/docs/docs/self-service/flows/user-settings/user-profile-management.mdx @@ -13,7 +13,7 @@ first. The `profile` strategy allows a user to change their identity traits ("profile"). -The updated traits must be valid against the JSON Schema defined for its +The updated traits must be valid against the Identity JSON Schema defined for its [Identity Traits](../../../concepts/identity-user-model). If one or more fields do not validate (e.g. "Not an email"), the profile will not be updated. @@ -80,7 +80,7 @@ The Settings Request Response Payload always includes a `profile` method: }, "identity": { "id": "93548b1b-c8dc-4d3e-b19f-cfc6d812a8d0", - "traits_schema_id": "default", + "schema_id": "default", "traits": { "email": "xx0bdh@l7zkk8", "website": "http://github.com/aeneasr" diff --git a/docs/docs/self-service/flows/verify-email-account-activation.mdx b/docs/docs/self-service/flows/verify-email-account-activation.mdx index 079bfc24ba6d..7a95160d9ebe 100644 --- a/docs/docs/self-service/flows/verify-email-account-activation.mdx +++ b/docs/docs/self-service/flows/verify-email-account-activation.mdx @@ -53,47 +53,57 @@ able to do in your application logic or API Gateways. ## Setting Email Verification You must define at least one Identity Traits field as a verification field. You -can do so by defining the following section in your Identity Traits JSON Schema: +can do so by defining the following section in your Identity JSON Schema: -```json5 title="path/to/identity.traits.schema.json" +```json5 title="path/to/identity.schema.json" { // ... properties: { - // This could also be an array or any other field name - email: { - type: 'string', - format: 'email', - 'ory.sh/kratos': { - verification: { - // Currently, only email is supported - via: 'email' + traits: { + type: "object", + properties: { + // This could also be an array or any other field name + email: { + type: 'string', + format: 'email', + 'ory.sh/kratos': { + verification: { + // Currently, only email is supported + via: 'email' + } + } } } } - } + }, // ... } ``` You can also combine this with the password strategy login identifier. -```json5 title="path/to/identity.traits.schema.json" +```json5 title="path/to/identity.schema.json" { // ... properties: { - // This could also be an array or any other field name - email: { - type: 'string', - format: 'email', - 'ory.sh/kratos': { - credentials: { - password: { - identifier: true + traits: { + type: "object", + properties: { + // This could also be an array or any other field name + email: { + type: 'string', + format: 'email', + 'ory.sh/kratos': { + credentials: { + password: { + identifier: true + } + }, + verification: { + // Currently, only email is supported + via: 'email' + } } - }, - verification: { - // Currently, only email is supported - via: 'email' } } } diff --git a/driver/configuration/provider_viper.go b/driver/configuration/provider_viper.go index ba9587625237..556db733cfc2 100644 --- a/driver/configuration/provider_viper.go +++ b/driver/configuration/provider_viper.go @@ -88,8 +88,8 @@ const ( ViperKeySelfServiceVerificationRequestLifespan = "selfservice.flows.verification.request_lifespan" ViperKeySelfServiceVerificationBrowserDefaultReturnTo = "selfservice.flows.verification.after." + DefaultBrowserReturnURL - ViperKeyDefaultIdentityTraitsSchemaURL = "identity.traits.default_schema_url" - ViperKeyIdentityTraitsSchemas = "identity.traits.schemas" + ViperKeyDefaultIdentitySchemaURL = "identity.default_schema_url" + ViperKeyIdentitySchemas = "identity.schemas" ViperKeyHasherArgon2ConfigMemory = "hashers.argon2.memory" ViperKeyHasherArgon2ConfigIterations = "hashers.argon2.iterations" @@ -131,7 +131,7 @@ func (p *ViperProvider) listenOn(key string) string { } func (p *ViperProvider) DefaultIdentityTraitsSchemaURL() *url.URL { - return mustParseURLFromViper(p.l, ViperKeyDefaultIdentityTraitsSchemaURL) + return mustParseURLFromViper(p.l, ViperKeyDefaultIdentitySchemaURL) } func (p *ViperProvider) IdentityTraitsSchemas() SchemaConfigs { @@ -141,18 +141,18 @@ func (p *ViperProvider) IdentityTraitsSchemas() SchemaConfigs { } var b bytes.Buffer var ss SchemaConfigs - raw := viper.Get(ViperKeyIdentityTraitsSchemas) + raw := viper.Get(ViperKeyIdentitySchemas) if raw == nil { return SchemaConfigs{ds} } if err := json.NewEncoder(&b).Encode(raw); err != nil { - p.l.WithError(err).Fatalf("Unable to encode values from %s.", ViperKeyIdentityTraitsSchemas) + p.l.WithError(err).Fatalf("Unable to encode values from %s.", ViperKeyIdentitySchemas) } if err := jsonx.NewStrictDecoder(&b).Decode(&ss); err != nil { - p.l.WithError(err).Fatalf("Unable to decode values from %s.", ViperKeyIdentityTraitsSchemas) + p.l.WithError(err).Fatalf("Unable to decode values from %s.", ViperKeyIdentitySchemas) } return append(ss, ds) diff --git a/driver/registry_default_schemas_test.go b/driver/registry_default_schemas_test.go index 7a99e38434e4..af490916ffa1 100644 --- a/driver/registry_default_schemas_test.go +++ b/driver/registry_default_schemas_test.go @@ -25,8 +25,8 @@ func TestRegistryDefault_IdentityTraitsSchemas(t *testing.T) { RawURL: "file://other.schema.json", } - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, defaultSchema.RawURL) - viper.Set(configuration.ViperKeyIdentityTraitsSchemas, []configuration.SchemaConfig{{ID: altSchema.ID, URL: altSchema.RawURL}}) + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, defaultSchema.RawURL) + viper.Set(configuration.ViperKeyIdentitySchemas, []configuration.SchemaConfig{{ID: altSchema.ID, URL: altSchema.RawURL}}) ss := reg.IdentityTraitsSchemas() assert.Equal(t, 2, len(ss)) diff --git a/go.mod b/go.mod index d9c822033728..97e1062551a4 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/ory/kratos go 1.14 +replace github.com/ory/x => ../x + require ( github.com/Masterminds/sprig/v3 v3.0.0 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect @@ -76,6 +78,7 @@ require ( github.com/stretchr/testify v1.5.1 github.com/tidwall/gjson v1.3.5 github.com/tidwall/sjson v1.0.4 + github.com/uber/jaeger-lib v2.2.0+incompatible // indirect github.com/urfave/negroni v1.0.0 go.mongodb.org/mongo-driver v1.3.3 // indirect golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 @@ -85,6 +88,7 @@ require ( golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d gopkg.in/go-playground/validator.v9 v9.28.0 + gopkg.in/gorp.v1 v1.7.2 // indirect gopkg.in/ini.v1 v1.56.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/identity/handler.go b/identity/handler.go index 1956bdcf2b62..441b97070e19 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -165,9 +165,9 @@ func (h *Handler) create(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - // Make sure the TraitsSchemaURL is only set by kratos - if i.TraitsSchemaURL != "" { - h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithReason("Use the traits_schema_id to set a traits schema.")) + // Make sure the SchemaURL is only set by kratos + if i.SchemaURL != "" { + h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithReason("Use the schema_id to set a traits schema.")) return } // We do not allow setting credentials using this method diff --git a/identity/handler_test.go b/identity/handler_test.go index ecac61382245..6656adc6dd3e 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -40,7 +40,7 @@ func TestHandler(t *testing.T) { defaultSchemaExternalURL := defaultSchema.SchemaURL(mockServerURL).String() viper.Set(configuration.ViperKeyAdminBaseURL, ts.URL) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, defaultSchemaInternalURL.String()) + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, defaultSchemaInternalURL.String()) viper.Set(configuration.ViperKeyPublicBaseURL, mockServerURL.String()) var get = func(t *testing.T, href string, expectCode int) gjson.Result { @@ -92,7 +92,7 @@ func TestHandler(t *testing.T) { t.Run("case=should fail to create an identity because schema id does not exist", func(t *testing.T) { var i identity.Identity - i.TraitsSchemaID = "does-not-exist" + i.SchemaID = "does-not-exist" res := send(t, "POST", "/identities", http.StatusBadRequest, &i) assert.Contains(t, res.Get("error.reason").String(), "does-not-exist", "%s", res) }) @@ -101,12 +101,12 @@ func TestHandler(t *testing.T) { var i identity.Identity i.Traits = identity.Traits(`{"bar":123}`) res := send(t, "POST", "/identities", http.StatusBadRequest, &i) - assert.Contains(t, res.Get("error.reason").String(), "I[#/traits/bar] S[#/properties/bar/type] expected string, but got number") + assert.Contains(t, res.Get("error.reason").String(), "I[#/traits/bar] S[#/properties/traits/properties/bar/type] expected string, but got number") }) - t.Run("case=should fail to create an entity with traits_schema_url set", func(t *testing.T) { + t.Run("case=should fail to create an entity with schema_url set", func(t *testing.T) { var i identity.Identity - i.TraitsSchemaURL = "http://example.com" + i.SchemaURL = "http://example.com" res := send(t, "POST", "/identities", http.StatusBadRequest, &i) assert.Contains(t, res.Get("error.reason").String(), "set a traits schema") }) @@ -130,16 +130,16 @@ func TestHandler(t *testing.T) { i.ID = x.ParseUUID(res.Get("id").String()) assert.EqualValues(t, "baz", res.Get("traits.bar").String(), "%s", res.Raw) assert.Empty(t, res.Get("credentials").String(), "%s", res.Raw) - assert.EqualValues(t, defaultSchemaExternalURL, res.Get("traits_schema_url").String(), "%s", res.Raw) - assert.EqualValues(t, configuration.DefaultIdentityTraitsSchemaID, res.Get("traits_schema_id").String(), "%s", res.Raw) + assert.EqualValues(t, defaultSchemaExternalURL, res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, configuration.DefaultIdentityTraitsSchemaID, res.Get("schema_id").String(), "%s", res.Raw) }) t.Run("case=should be able to get the identity", func(t *testing.T) { res := get(t, "/identities/"+i.ID.String(), http.StatusOK) assert.EqualValues(t, i.ID.String(), res.Get("id").String(), "%s", res.Raw) assert.EqualValues(t, "baz", res.Get("traits.bar").String(), "%s", res.Raw) - assert.EqualValues(t, defaultSchemaExternalURL, res.Get("traits_schema_url").String(), "%s", res.Raw) - assert.EqualValues(t, configuration.DefaultIdentityTraitsSchemaID, res.Get("traits_schema_id").String(), "%s", res.Raw) + assert.EqualValues(t, defaultSchemaExternalURL, res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, configuration.DefaultIdentityTraitsSchemaID, res.Get("schema_id").String(), "%s", res.Raw) assert.Empty(t, res.Get("credentials").String(), "%s", res.Raw) }) diff --git a/identity/identity.go b/identity/identity.go index 4f762c3e5c2c..c2e791459177 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -38,19 +38,19 @@ type ( // Credentials represents all credentials that can be used for authenticating this identity. Credentials map[CredentialsType]Credentials `json:"-" faker:"-" db:"-"` - // TraitsSchemaID is the ID of the JSON Schema to be used for validating the identity's traits. + // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. // // required: true - TraitsSchemaID string `json:"traits_schema_id" faker:"-" db:"traits_schema_id"` + SchemaID string `json:"schema_id" faker:"-" db:"schema_id"` - // TraitsSchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. + // SchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. // // format: url - TraitsSchemaURL string `json:"traits_schema_url" faker:"-" db:"-"` + SchemaURL string `json:"schema_url" faker:"-" db:"-"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits // in a self-service manner. The input will always be validated against the JSON Schema defined - // in `traits_schema_url`. + // in `schema_url`. // // required: true Traits Traits `json:"traits" faker:"-" db:"traits"` @@ -170,7 +170,7 @@ func NewIdentity(traitsSchemaID string) *Identity { ID: x.NewUUID(), Credentials: map[CredentialsType]Credentials{}, Traits: Traits("{}"), - TraitsSchemaID: traitsSchemaID, + SchemaID: traitsSchemaID, VerifiableAddresses: []VerifiableAddress{}, l: new(sync.RWMutex), } diff --git a/identity/manager_test.go b/identity/manager_test.go index a7051567b3d0..dd32531bb355 100644 --- a/identity/manager_test.go +++ b/identity/manager_test.go @@ -18,7 +18,7 @@ import ( func TestManager(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/manager.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/manager.schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh/") viper.Set(configuration.ViperKeyCourierSMTPURL, "smtp://foo@bar@dev.null/") diff --git a/identity/pool.go b/identity/pool.go index 2fe6c3e39117..72ac30daf992 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -93,8 +93,8 @@ func TestPool(p PrivilegedPool) func(t *testing.T) { URL: urlx.ParseOrPanic("file://./stub/identity-2.schema.json"), RawURL: "file://./stub/identity-2.schema.json", } - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, defaultSchema.RawURL) - viper.Set(configuration.ViperKeyIdentityTraitsSchemas, []configuration.SchemaConfig{{ + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, defaultSchema.RawURL) + viper.Set(configuration.ViperKeyIdentitySchemas, []configuration.SchemaConfig{{ ID: altSchema.ID, URL: altSchema.RawURL, }}) @@ -146,8 +146,8 @@ func TestPool(p PrivilegedPool) func(t *testing.T) { require.NoError(t, err) assert.Equal(t, expected.ID, actual.ID) - assert.Equal(t, configuration.DefaultIdentityTraitsSchemaID, actual.TraitsSchemaID) - assert.Equal(t, defaultSchema.SchemaURL(exampleServerURL).String(), actual.TraitsSchemaURL) + assert.Equal(t, configuration.DefaultIdentityTraitsSchemaID, actual.SchemaID) + assert.Equal(t, defaultSchema.SchemaURL(exampleServerURL).String(), actual.SchemaURL) assertEqual(t, expected, actual) }) @@ -169,8 +169,8 @@ func TestPool(p PrivilegedPool) func(t *testing.T) { actual, err := p.GetIdentity(context.Background(), expected.ID) require.NoError(t, err) - assert.Equal(t, altSchema.ID, actual.TraitsSchemaID) - assert.Equal(t, altSchema.SchemaURL(exampleServerURL).String(), actual.TraitsSchemaURL) + assert.Equal(t, altSchema.ID, actual.SchemaID) + assert.Equal(t, altSchema.SchemaURL(exampleServerURL).String(), actual.SchemaURL) assertEqual(t, expected, actual) actual, err = p.GetIdentityConfidential(context.Background(), expected.ID) @@ -250,8 +250,8 @@ func TestPool(p PrivilegedPool) func(t *testing.T) { require.NoError(t, p.CreateIdentity(context.Background(), initial)) createdIDs = append(createdIDs, initial.ID) - assert.Equal(t, configuration.DefaultIdentityTraitsSchemaID, initial.TraitsSchemaID) - assert.Equal(t, defaultSchema.SchemaURL(exampleServerURL).String(), initial.TraitsSchemaURL) + assert.Equal(t, configuration.DefaultIdentityTraitsSchemaID, initial.SchemaID) + assert.Equal(t, defaultSchema.SchemaURL(exampleServerURL).String(), initial.SchemaURL) expected := initial.CopyWithoutCredentials() expected.SetCredentials(CredentialsTypePassword, Credentials{ @@ -260,13 +260,13 @@ func TestPool(p PrivilegedPool) func(t *testing.T) { Config: sqlxx.JSONRawMessage(`{"oh":"nono"}`), }) expected.Traits = Traits(`{"update":"me"}`) - expected.TraitsSchemaID = altSchema.ID + expected.SchemaID = altSchema.ID require.NoError(t, p.UpdateIdentity(context.Background(), expected)) actual, err := p.GetIdentityConfidential(context.Background(), expected.ID) require.NoError(t, err) - assert.Equal(t, altSchema.ID, actual.TraitsSchemaID) - assert.Equal(t, altSchema.SchemaURL(exampleServerURL).String(), actual.TraitsSchemaURL) + assert.Equal(t, altSchema.ID, actual.SchemaID) + assert.Equal(t, altSchema.SchemaURL(exampleServerURL).String(), actual.SchemaURL) assert.NotEmpty(t, actual.Credentials[CredentialsTypePassword]) assert.Empty(t, actual.Credentials[CredentialsTypeOIDC]) diff --git a/identity/stub/extension.schema.json b/identity/stub/extension.schema.json index b9447a7d8574..512854ca2124 100644 --- a/identity/stub/extension.schema.json +++ b/identity/stub/extension.schema.json @@ -4,38 +4,46 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } - } - } - }, - "names": { - "type": "array", - "items": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + }, + "names": { + "type": "array", + "items": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 1 } - } - }, - "age": { - "description": "Age in years which must be equal to or greater than zero.", - "type": "integer", - "minimum": 1 + }, + "required": [ + "email" + ] } }, "required": [ - "email" + "traits" ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/identity/stub/identity-2.schema.json b/identity/stub/identity-2.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/identity/stub/identity-2.schema.json +++ b/identity/stub/identity-2.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/identity/stub/identity.schema.json b/identity/stub/identity.schema.json index fe94126c9526..0337894a884f 100644 --- a/identity/stub/identity.schema.json +++ b/identity/stub/identity.schema.json @@ -4,15 +4,20 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" - }, - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + }, + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } diff --git a/identity/stub/manager.schema.json b/identity/stub/manager.schema.json index 1af96fb859bb..4bb7b5486c33 100644 --- a/identity/stub/manager.schema.json +++ b/identity/stub/manager.schema.json @@ -4,46 +4,51 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } } }, - "verification": { - "via": "email" - } - } - }, - "email_creds": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "email_creds": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "email_verify": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "verification": { + "via": "email" + } + } + }, + "unprotected": { + "type": "string" } - } - }, - "email_verify": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "verification": { - "via": "email" - } - } - }, - "unprotected": { - "type": "string" + }, + "required": [ + "email" + ] } }, - "required": [ - "email" - ], "additionalProperties": false } diff --git a/identity/validator.go b/identity/validator.go index 2ae297416e83..03d3a7bb9885 100644 --- a/identity/validator.go +++ b/identity/validator.go @@ -1,11 +1,7 @@ package identity import ( - "encoding/json" - - "github.com/ory/jsonschema/v3" - - "github.com/ory/x/errorsx" + "github.com/tidwall/sjson" "github.com/ory/kratos/driver/configuration" "github.com/ory/kratos/schema" @@ -39,23 +35,17 @@ func (v *Validator) ValidateWithRunner(i *Identity, runners ...schema.Extension) return err } - s, err := v.d.IdentityTraitsSchemas().GetByID(i.TraitsSchemaID) + s, err := v.d.IdentityTraitsSchemas().GetByID(i.SchemaID) if err != nil { return err } - err = v.v.Validate( - s.URL.String(), - json.RawMessage(i.Traits), - schema.WithExtensionRunner(runner), - ) - - switch e := errorsx.Cause(err).(type) { - case *jsonschema.ValidationError: - return schema.ContextSetRoot(e, "traits") + traits, err := sjson.SetRawBytes([]byte(`{}`), "traits", i.Traits) + if err != nil { + return err } - return err + return v.v.Validate(s.URL.String(), traits, schema.WithExtensionRunner(runner)) } func (v *Validator) Validate(i *Identity) error { diff --git a/identity/validator_test.go b/identity/validator_test.go index 6d174593488a..a0d7a25ef2c3 100644 --- a/identity/validator_test.go +++ b/identity/validator_test.go @@ -29,19 +29,25 @@ func TestSchemaValidator(t *testing.T) { "title": "Person", "type": "object", "properties": { - "` + ps.ByName("name") + `": { - "type": "string", - "description": "The person's first name." - }, - "lastName": { - "type": "string", - "description": "The person's last name." - }, - "age": { - "description": "Age in years which must be equal to or greater than zero.", - "type": "integer", - "minimum": 1 - } + "traits": { + "type": "object", + "properties": { + "` + ps.ByName("name") + `": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 1 + } + }, + "additionalProperties": false + } }, "additionalProperties": false }`)) @@ -51,8 +57,8 @@ func TestSchemaValidator(t *testing.T) { defer ts.Close() conf, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, ts.URL+"/schema/firstName") - viper.Set(configuration.ViperKeyIdentityTraitsSchemas, []configuration.SchemaConfig{ + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, ts.URL+"/schema/firstName") + viper.Set(configuration.ViperKeyIdentitySchemas, []configuration.SchemaConfig{ {ID: "whatever", URL: ts.URL + "/schema/whatever"}, {ID: "unreachable-url", URL: ts.URL + "/404-not-found"}, }) @@ -71,31 +77,31 @@ func TestSchemaValidator(t *testing.T) { i: &Identity{ Traits: Traits(`{ "firstName": "first-name", "lastName": "last-name", "age": -1 }`), }, - err: "I[#/traits/age] S[#/properties/age/minimum] must be >= 1 but found -1", + err: "I[#/traits/age] S[#/properties/traits/properties/age/minimum] must be >= 1 but found -1", }, { i: &Identity{ Traits: Traits(`{ "whatever": "first-name", "lastName": "last-name", "age": 1 }`), }, - err: `I[#/traits] S[#/additionalProperties] additionalProperties "whatever" not allowed`, + err: `I[#/traits] S[#/properties/traits/additionalProperties] additionalProperties "whatever" not allowed`, }, { i: &Identity{ - TraitsSchemaID: "whatever", - Traits: Traits(`{ "whatever": "first-name", "lastName": "last-name", "age": 1 }`), + SchemaID: "whatever", + Traits: Traits(`{ "whatever": "first-name", "lastName": "last-name", "age": 1 }`), }, }, { i: &Identity{ - TraitsSchemaID: "whatever", - Traits: Traits(`{ "firstName": "first-name", "lastName": "last-name", "age": 1 }`), + SchemaID: "whatever", + Traits: Traits(`{ "firstName": "first-name", "lastName": "last-name", "age": 1 }`), }, - err: `I[#/traits] S[#/additionalProperties] additionalProperties "firstName" not allowed`, + err: `I[#/traits] S[#/properties/traits/additionalProperties] additionalProperties "firstName" not allowed`, }, { i: &Identity{ - TraitsSchemaID: "unreachable-url", - Traits: Traits(`{ "firstName": "first-name", "lastName": "last-name", "age": 1 }`), + SchemaID: "unreachable-url", + Traits: Traits(`{ "firstName": "first-name", "lastName": "last-name", "age": 1 }`), }, err: "An internal server error occurred, please contact the system administrator", }, diff --git a/internal/.kratos.yaml b/internal/.kratos.yaml index 99cfd0c67fbd..96ff56b54066 100644 --- a/internal/.kratos.yaml +++ b/internal/.kratos.yaml @@ -19,11 +19,10 @@ courier: connection_uri: smtp://foo:bar@baz/ identity: - traits: - default_schema_url: http://test.kratos.ory.sh/default-identity.schema.json - schemas: - - id: other - url: http://test.kratos.ory.sh/other-identity.schema.json + default_schema_url: http://test.kratos.ory.sh/default-identity.schema.json + schemas: + - id: other + url: http://test.kratos.ory.sh/other-identity.schema.json hashers: argon2: diff --git a/internal/httpclient/models/identity.go b/internal/httpclient/models/identity.go index 60c8a4ce6f53..c4fc73bf731e 100644 --- a/internal/httpclient/models/identity.go +++ b/internal/httpclient/models/identity.go @@ -27,18 +27,18 @@ type Identity struct { // RecoveryAddresses contains all the addresses that can be used to recover an identity. RecoveryAddresses []*RecoveryAddress `json:"recovery_addresses"` - // traits - // Required: true - Traits Traits `json:"traits"` - - // TraitsSchemaID is the ID of the JSON Schema to be used for validating the identity's traits. + // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. // Required: true - TraitsSchemaID *string `json:"traits_schema_id"` + SchemaID *string `json:"schema_id"` - // TraitsSchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. + // SchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. // // format: url - TraitsSchemaURL string `json:"traits_schema_url,omitempty"` + SchemaURL string `json:"schema_url,omitempty"` + + // traits + // Required: true + Traits Traits `json:"traits"` // VerifiableAddresses contains all the addresses that can be verified by the user. VerifiableAddresses []*VerifiableAddress `json:"verifiable_addresses"` @@ -56,11 +56,11 @@ func (m *Identity) Validate(formats strfmt.Registry) error { res = append(res, err) } - if err := m.validateTraits(formats); err != nil { + if err := m.validateSchemaID(formats); err != nil { res = append(res, err) } - if err := m.validateTraitsSchemaID(formats); err != nil { + if err := m.validateTraits(formats); err != nil { res = append(res, err) } @@ -111,18 +111,18 @@ func (m *Identity) validateRecoveryAddresses(formats strfmt.Registry) error { return nil } -func (m *Identity) validateTraits(formats strfmt.Registry) error { +func (m *Identity) validateSchemaID(formats strfmt.Registry) error { - if err := validate.Required("traits", "body", m.Traits); err != nil { + if err := validate.Required("schema_id", "body", m.SchemaID); err != nil { return err } return nil } -func (m *Identity) validateTraitsSchemaID(formats strfmt.Registry) error { +func (m *Identity) validateTraits(formats strfmt.Registry) error { - if err := validate.Required("traits_schema_id", "body", m.TraitsSchemaID); err != nil { + if err := validate.Required("traits", "body", m.Traits); err != nil { return err } diff --git a/internal/testhelpers/handler_mock.go b/internal/testhelpers/handler_mock.go index f75f59c0d76b..32a9d894ad09 100644 --- a/internal/testhelpers/handler_mock.go +++ b/internal/testhelpers/handler_mock.go @@ -100,8 +100,8 @@ func MockSessionCreateHandlerWithIdentity(t *testing.T, reg mockDeps, i *identit sess.IssuedAt = time.Now().UTC() sess.ExpiresAt = time.Now().UTC().Add(time.Hour * 24) - if viper.GetString(configuration.ViperKeyDefaultIdentityTraitsSchemaURL) == "" { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/fake-session.schema.json") + if viper.GetString(configuration.ViperKeyDefaultIdentitySchemaURL) == "" { + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/fake-session.schema.json") } require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) diff --git a/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json b/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json index 6d366648c423..34d2e511e8eb 100644 --- a/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json +++ b/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json @@ -1,7 +1,7 @@ { "id": "5ff66179-c240-4703-b0d8-494592cefff5", - "traits_schema_id": "default", - "traits_schema_url": "https://www.ory.sh/schemas/default", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/default", "traits": { "email": "bazbar@ory.sh" }, diff --git a/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json b/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json index e1489dd8d1bd..8ea1314dfc57 100644 --- a/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json +++ b/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json @@ -1,7 +1,7 @@ { "id": "a251ebc2-880c-4f76-a8f3-38e6940eab0e", - "traits_schema_id": "default", - "traits_schema_url": "https://www.ory.sh/schemas/default", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/default", "traits": { "email": "foobar@ory.sh" }, diff --git a/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json b/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json new file mode 100644 index 000000000000..a48eaf22723a --- /dev/null +++ b/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json @@ -0,0 +1,8 @@ +{ + "id": "d7b9addb-ac15-4bc2-9fa5-562e0bf48755", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/default", + "traits": { + "email": "d7b9@ory.sh" + } +} \ No newline at end of file diff --git a/persistence/sql/migratest/fixtures/settings_request/194c5b05-0487-4a11-bcbc-f301c9ff9678.json b/persistence/sql/migratest/fixtures/settings_request/194c5b05-0487-4a11-bcbc-f301c9ff9678.json index 935682a31905..058de6e71c52 100644 --- a/persistence/sql/migratest/fixtures/settings_request/194c5b05-0487-4a11-bcbc-f301c9ff9678.json +++ b/persistence/sql/migratest/fixtures/settings_request/194c5b05-0487-4a11-bcbc-f301c9ff9678.json @@ -63,8 +63,8 @@ }, "identity": { "id": "a251ebc2-880c-4f76-a8f3-38e6940eab0e", - "traits_schema_id": "default", - "traits_schema_url": "", + "schema_id": "default", + "schema_url": "", "traits": { "email": "foobar@ory.sh" } diff --git a/persistence/sql/migratest/fixtures/settings_request/21c5f714-3089-49d2-b387-f244d4dd9e00.json b/persistence/sql/migratest/fixtures/settings_request/21c5f714-3089-49d2-b387-f244d4dd9e00.json index 3615dd3aed61..4cecd079a553 100644 --- a/persistence/sql/migratest/fixtures/settings_request/21c5f714-3089-49d2-b387-f244d4dd9e00.json +++ b/persistence/sql/migratest/fixtures/settings_request/21c5f714-3089-49d2-b387-f244d4dd9e00.json @@ -64,8 +64,8 @@ }, "identity": { "id": "a251ebc2-880c-4f76-a8f3-38e6940eab0e", - "traits_schema_id": "default", - "traits_schema_url": "", + "schema_id": "default", + "schema_url": "", "traits": { "email": "foobar@ory.sh" } diff --git a/persistence/sql/migratest/fixtures/settings_request/74fd6c53-7651-453e-90b8-2c5adbf911bb.json b/persistence/sql/migratest/fixtures/settings_request/74fd6c53-7651-453e-90b8-2c5adbf911bb.json index aca140e113c3..07ac3698a62a 100644 --- a/persistence/sql/migratest/fixtures/settings_request/74fd6c53-7651-453e-90b8-2c5adbf911bb.json +++ b/persistence/sql/migratest/fixtures/settings_request/74fd6c53-7651-453e-90b8-2c5adbf911bb.json @@ -63,8 +63,8 @@ }, "identity": { "id": "5ff66179-c240-4703-b0d8-494592cefff5", - "traits_schema_id": "default", - "traits_schema_url": "", + "schema_id": "default", + "schema_url": "", "traits": { "email": "bazbar@ory.sh" } diff --git a/persistence/sql/migratest/fixtures/settings_request/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json b/persistence/sql/migratest/fixtures/settings_request/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json index 6ce62d26a929..c8c9bf8d2d50 100644 --- a/persistence/sql/migratest/fixtures/settings_request/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json +++ b/persistence/sql/migratest/fixtures/settings_request/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json @@ -8,8 +8,8 @@ "methods": {}, "identity": { "id": "a251ebc2-880c-4f76-a8f3-38e6940eab0e", - "traits_schema_id": "default", - "traits_schema_url": "", + "schema_id": "default", + "schema_url": "", "traits": { "email": "foobar@ory.sh" } diff --git a/persistence/sql/migratest/fixtures/settings_request/a79bfcf1-68ae-49de-8b23-4f96921b8341.json b/persistence/sql/migratest/fixtures/settings_request/a79bfcf1-68ae-49de-8b23-4f96921b8341.json index 50ee38d16599..1cdaded4543a 100644 --- a/persistence/sql/migratest/fixtures/settings_request/a79bfcf1-68ae-49de-8b23-4f96921b8341.json +++ b/persistence/sql/migratest/fixtures/settings_request/a79bfcf1-68ae-49de-8b23-4f96921b8341.json @@ -8,8 +8,8 @@ "methods": {}, "identity": { "id": "a251ebc2-880c-4f76-a8f3-38e6940eab0e", - "traits_schema_id": "default", - "traits_schema_url": "", + "schema_id": "default", + "schema_url": "", "traits": { "email": "foobar@ory.sh" } diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index d077cf4d00c1..26ae8a917582 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -51,7 +51,7 @@ func TestMigrations(t *testing.T) { l := logrusx.New("", "", logrusx.ForceLevel(logrus.TraceLevel)) plog.Logger = gobuffalologger.Logrus{FieldLogger: l.Entry} - if !testing.Short() { + if !testing.Short() && false { dockertest.Parallel([]func(){ func() { connections["postgres"] = dockertest.ConnectToTestPostgreSQLPop(t) @@ -93,11 +93,20 @@ func TestMigrations(t *testing.T) { } t.Logf("URL: %s", url) + var isSQLite = c.Dialect.Name() == "sqlite3" + tm := popx.NewTestMigrator(t, c, "../migrations/sql", "./testdata") + + if isSQLite { + require.NoError(t, c.RawQuery(`PRAGMA legacy_alter_table=on; PRAGMA foreign_keys=off;`).Exec()) + } require.NoError(t, tm.Up()) + if isSQLite { + require.NoError(t, c.RawQuery(`PRAGMA legacy_alter_table=off; PRAGMA foreign_keys=on;`).Exec()) + } viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh/") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://stub/default.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://stub/default.schema.json") viper.Set(configuration.ViperKeyDSN, url) d, err := driver.NewDefaultDriver(l, "", "", "", true) diff --git a/persistence/sql/migratest/stub/default.schema.json b/persistence/sql/migratest/stub/default.schema.json index 25c8aa1230f2..241b41c077ad 100644 --- a/persistence/sql/migratest/stub/default.schema.json +++ b/persistence/sql/migratest/stub/default.schema.json @@ -4,6 +4,10 @@ "title": "Person", "type": "object", "properties": { + "traits": { + "type": "object", + "properties": { + "email": { "type": "string", "ory.sh/kratos": { @@ -20,5 +24,7 @@ } } } + } + } } } diff --git a/persistence/sql/migratest/testdata/20200705105359_testdata.sql b/persistence/sql/migratest/testdata/20200705105359_testdata.sql new file mode 100644 index 000000000000..7fe4f7b6cc44 --- /dev/null +++ b/persistence/sql/migratest/testdata/20200705105359_testdata.sql @@ -0,0 +1 @@ +INSERT INTO identities (id, schema_id, traits, created_at, updated_at) VALUES ('d7b9addb-ac15-4bc2-9fa5-562e0bf48755', 'default', '{"email":"d7b9@ory.sh"}', '2013-10-07 08:23:19', '2013-10-07 08:23:19'); diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.down.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.down.sql new file mode 100644 index 000000000000..07a1c56fadd2 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.down.sql @@ -0,0 +1 @@ +ALTER TABLE "identities" RENAME COLUMN "schema_id" TO "traits_schema_id";COMMIT TRANSACTION;BEGIN TRANSACTION; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.up.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.up.sql new file mode 100644 index 000000000000..fc35d52520a9 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.cockroach.up.sql @@ -0,0 +1 @@ +ALTER TABLE "identities" RENAME COLUMN "traits_schema_id" TO "schema_id";COMMIT TRANSACTION;BEGIN TRANSACTION; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.down.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.down.sql new file mode 100644 index 000000000000..7e3303f96228 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.down.sql @@ -0,0 +1 @@ +ALTER TABLE `identities` CHANGE `schema_id` `traits_schema_id` varchar(2048) NOT NULL; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.up.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.up.sql new file mode 100644 index 000000000000..92a92fa94fe3 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.mysql.up.sql @@ -0,0 +1 @@ +ALTER TABLE `identities` CHANGE `traits_schema_id` `schema_id` varchar(2048) NOT NULL; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.down.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.down.sql new file mode 100644 index 000000000000..d2dee7d0fd08 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.down.sql @@ -0,0 +1 @@ +ALTER TABLE "identities" RENAME COLUMN "schema_id" TO "traits_schema_id"; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.up.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.up.sql new file mode 100644 index 000000000000..ce7cd59733a5 --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.postgres.up.sql @@ -0,0 +1 @@ +ALTER TABLE "identities" RENAME COLUMN "traits_schema_id" TO "schema_id"; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.down.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.down.sql new file mode 100644 index 000000000000..270c241d600e --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.down.sql @@ -0,0 +1,10 @@ +ALTER TABLE "identities" RENAME TO "_identities_tmp"; +CREATE TABLE "identities" ( +"id" TEXT PRIMARY KEY, +"traits_schema_id" TEXT NOT NULL, +"traits" TEXT NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL +); +INSERT INTO "identities" (id, traits_schema_id, traits, created_at, updated_at) SELECT id, schema_id, traits, created_at, updated_at FROM "_identities_tmp"; +DROP TABLE "_identities_tmp"; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.up.sql b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.up.sql new file mode 100644 index 000000000000..cac1d587ad4c --- /dev/null +++ b/persistence/sql/migrations/sql/20200705105359_rename_identities_schema.sqlite3.up.sql @@ -0,0 +1,10 @@ +ALTER TABLE "identities" RENAME TO "_identities_tmp"; +CREATE TABLE "identities" ( +"id" TEXT PRIMARY KEY, +"schema_id" TEXT NOT NULL, +"traits" TEXT NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL +); +INSERT INTO "identities" (id, schema_id, traits, created_at, updated_at) SELECT id, traits_schema_id, traits, created_at, updated_at FROM "_identities_tmp"; +DROP TABLE "_identities_tmp"; \ No newline at end of file diff --git a/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.down.fizz b/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.down.fizz new file mode 100644 index 000000000000..ed0715fca890 --- /dev/null +++ b/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.down.fizz @@ -0,0 +1 @@ +rename_column("identities", "schema_id", "traits_schema_id") diff --git a/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.up.fizz b/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.up.fizz new file mode 100644 index 000000000000..5a9159b835a1 --- /dev/null +++ b/persistence/sql/migrations/templates/20200705105359_rename_identities_schema.up.fizz @@ -0,0 +1 @@ +rename_column("identities", "traits_schema_id", "schema_id") diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index dd322c0cbb9b..cafe778c8044 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -25,10 +25,11 @@ type ( x.LoggingProvider } Persister struct { - c *pop.Connection - mb pop.MigrationBox - r persisterDependencies - cf configuration.Provider + c *pop.Connection + mb pop.MigrationBox + r persisterDependencies + cf configuration.Provider + isSQLite bool } ) @@ -38,7 +39,7 @@ func NewPersister(r persisterDependencies, conf configuration.Provider, c *pop.C return nil, errors.WithStack(err) } - return &Persister{c: c, mb: m, cf: conf, r: r}, nil + return &Persister{c: c, mb: m, cf: conf, r: r, isSQLite: c.Dialect.Name() == "sqlite3"}, nil } func (p *Persister) Connection() *pop.Connection { @@ -50,10 +51,36 @@ func (p *Persister) MigrationStatus(ctx context.Context, w io.Writer) error { } func (p *Persister) MigrateDown(ctx context.Context, steps int) error { + // FIXME https://github.com/gobuffalo/pop/issues/574 + if p.isSQLite { + if err := p.c.RawQuery(`PRAGMA legacy_alter_table=on; PRAGMA foreign_keys=off;`).Exec(); err != nil { + return errors.WithStack(err) + } + + if err := p.mb.Down(steps); err != nil { + return errors.WithStack(err) + } + + return p.c.RawQuery(`PRAGMA legacy_alter_table=off; PRAGMA foreign_keys=on;`).Exec() + } + return errors.WithStack(p.mb.Down(steps)) } func (p *Persister) MigrateUp(ctx context.Context) error { + // FIXME https://github.com/gobuffalo/pop/issues/574 + if p.isSQLite { + if err := p.c.RawQuery(`PRAGMA legacy_alter_table=on; PRAGMA foreign_keys=off;`).Exec(); err != nil { + return errors.WithStack(err) + } + + if err := p.mb.Up(); err != nil { + return errors.WithStack(err) + } + + return p.c.RawQuery(`PRAGMA legacy_alter_table=off; PRAGMA foreign_keys=on;`).Exec() + } + return errors.WithStack(p.mb.Up()) } diff --git a/persistence/sql/persister_hmac_test.go b/persistence/sql/persister_hmac_test.go index 6e11c0d080ef..afe7f8b5a1a3 100644 --- a/persistence/sql/persister_hmac_test.go +++ b/persistence/sql/persister_hmac_test.go @@ -3,6 +3,7 @@ package sql import ( "testing" + "github.com/gobuffalo/pop/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -14,7 +15,9 @@ import ( func TestPersisterHMAC(t *testing.T) { viper.Set(configuration.ViperKeySecretsDefault, []string{"foobarbaz"}) - p, err := NewPersister(nil, configuration.NewViperProvider(logrusx.New("", ""), false), nil) + c, err := pop.NewConnection(&pop.ConnectionDetails{URL: "sqlite://foo?mode=memory"}) + require.NoError(t, err) + p, err := NewPersister(nil, configuration.NewViperProvider(logrusx.New("", ""), false), c) require.NoError(t, err) assert.True(t, p.hmacConstantCompare("hashme", p.hmacValue("hashme"))) diff --git a/persistence/sql/persister_identity.go b/persistence/sql/persister_identity.go index f14e21ba9303..c00d794417e8 100644 --- a/persistence/sql/persister_identity.go +++ b/persistence/sql/persister_identity.go @@ -141,8 +141,8 @@ func createRecoveryAddresses(ctx context.Context, tx *pop.Connection, i *identit } func (p *Persister) CreateIdentity(ctx context.Context, i *identity.Identity) error { - if i.TraitsSchemaID == "" { - i.TraitsSchemaID = configuration.DefaultIdentityTraitsSchemaID + if i.SchemaID == "" { + i.SchemaID = configuration.DefaultIdentityTraitsSchemaID } if len(i.Traits) == 0 { @@ -360,11 +360,11 @@ func (p *Persister) validateIdentity(i *identity.Identity) error { } func (p *Persister) injectTraitsSchemaURL(i *identity.Identity) error { - s, err := p.r.IdentityTraitsSchemas().GetByID(i.TraitsSchemaID) + s, err := p.r.IdentityTraitsSchemas().GetByID(i.SchemaID) if err != nil { return errors.WithStack(herodot.ErrInternalServerError.WithReasonf( - `The JSON Schema "%s" for this identity's traits could not be found.`, i.TraitsSchemaID)) + `The JSON Schema "%s" for this identity's traits could not be found.`, i.SchemaID)) } - i.TraitsSchemaURL = s.SchemaURL(p.cf.SelfPublicURL()).String() + i.SchemaURL = s.SchemaURL(p.cf.SelfPublicURL()).String() return nil } diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index 38447790b78c..a75d9c766114 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -93,7 +93,7 @@ func TestPersister(t *testing.T) { } var l sync.Mutex - if !testing.Short() { + if !testing.Short() && false { funcs := map[string]func(t *testing.T) string{ "postgres": dockertest.RunTestPostgreSQL, "mysql": dockertest.RunTestMySQL, diff --git a/persistence/sql/stub/identity-2.schema.json b/persistence/sql/stub/identity-2.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/persistence/sql/stub/identity-2.schema.json +++ b/persistence/sql/stub/identity-2.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/persistence/sql/stub/identity.schema.json b/persistence/sql/stub/identity.schema.json index fe94126c9526..0337894a884f 100644 --- a/persistence/sql/stub/identity.schema.json +++ b/persistence/sql/stub/identity.schema.json @@ -4,15 +4,20 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" - }, - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + }, + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } diff --git a/schema/handler_test.go b/schema/handler_test.go index 56ed99a8907a..8b1c1d41d35e 100644 --- a/schema/handler_test.go +++ b/schema/handler_test.go @@ -93,8 +93,8 @@ func TestHandler(t *testing.T) { } viper.Set(configuration.ViperKeyPublicBaseURL, ts.URL) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, getSchemaById(configuration.DefaultIdentityTraitsSchemaID).RawURL) - viper.Set(configuration.ViperKeyIdentityTraitsSchemas, schemasConfig) + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, getSchemaById(configuration.DefaultIdentityTraitsSchemaID).RawURL) + viper.Set(configuration.ViperKeyIdentitySchemas, schemasConfig) t.Run("case=get default schema", func(t *testing.T) { server := getFromTS(configuration.DefaultIdentityTraitsSchemaID, http.StatusOK) diff --git a/schema/schema_test.go b/schema/schema_test.go index 2b78465cc452..f974f0800844 100644 --- a/schema/schema_test.go +++ b/schema/schema_test.go @@ -74,9 +74,12 @@ func TestGetKeysInOrder(t *testing.T) { for i, tc := range []struct { schemaRef string keys []string + path string }{ {schemaRef: "file://./stub/identity.schema.json", keys: []string{"bar", "email"}}, - {schemaRef: "file://./stub/complex.schema.json", keys: []string{"meal.name", "meal.chef", "fruits", "vegetables"}}, + {schemaRef: "file://./stub/complex.schema.json", keys: []string{"meal.name", "meal.chef", "traits.email", + "traits.stringy", "traits.numby", "traits.booly", "traits.should_big_number", "traits.should_long_string", + "fruits", "vegetables"}}, } { t.Run(fmt.Sprintf("case=%d schemaRef=%s", i, tc.schemaRef), func(t *testing.T) { actual, err := GetKeysInOrder(tc.schemaRef) diff --git a/schema/stub/complex.schema.json b/schema/stub/complex.schema.json index 989823be8f9f..7afe6e9f0973 100644 --- a/schema/stub/complex.schema.json +++ b/schema/stub/complex.schema.json @@ -16,6 +16,41 @@ } } }, + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } + } + }, + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 + } + } + }, "fruits": { "type": "array", "items": { diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index e14c2b31014b..c1d9ed21f51f 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -38,7 +38,7 @@ func TestHandlerSettingForced(t *testing.T) { loginTS := testhelpers.NewLoginUIRequestEchoServer(t, reg) viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/login.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/login.schema.json") // assert bool ab := func(body []byte, exp bool) { diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index cad32d8318e9..391c9b10bfcc 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -28,7 +28,7 @@ func TestLoginExecutor(t *testing.T) { } { t.Run("strategy="+strategy, func(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/login.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/login.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") newServer := func(t *testing.T) *httptest.Server { diff --git a/selfservice/flow/login/stub/fake-session.schema.json b/selfservice/flow/login/stub/fake-session.schema.json index 558106d35900..bbcc9f405c56 100644 --- a/selfservice/flow/login/stub/fake-session.schema.json +++ b/selfservice/flow/login/stub/fake-session.schema.json @@ -3,5 +3,9 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", - "properties": {} + "properties": { + "traits": { + "type": "object" + } + } } diff --git a/selfservice/flow/login/stub/login.schema.json b/selfservice/flow/login/stub/login.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/login/stub/login.schema.json +++ b/selfservice/flow/login/stub/login.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/login/stub/registration.schema.json b/selfservice/flow/login/stub/registration.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/login/stub/registration.schema.json +++ b/selfservice/flow/login/stub/registration.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/login/stub/updated.schema.json b/selfservice/flow/login/stub/updated.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/login/stub/updated.schema.json +++ b/selfservice/flow/login/stub/updated.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/logout/handler_test.go b/selfservice/flow/logout/handler_test.go index 999eea818511..072d3ad8fe99 100644 --- a/selfservice/flow/logout/handler_test.go +++ b/selfservice/flow/logout/handler_test.go @@ -29,7 +29,7 @@ func TestLogoutHandler(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) handler := reg.LogoutHandler() - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "http://example.com") router := x.NewRouterPublic() diff --git a/selfservice/flow/logout/stub/registration.schema.json b/selfservice/flow/logout/stub/registration.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/logout/stub/registration.schema.json +++ b/selfservice/flow/logout/stub/registration.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/recovery/handler_test.go b/selfservice/flow/recovery/handler_test.go index ee80e4c16729..dba6fa2d96b1 100644 --- a/selfservice/flow/recovery/handler_test.go +++ b/selfservice/flow/recovery/handler_test.go @@ -38,7 +38,7 @@ func TestHandlerRedirectOnAuthenticated(t *testing.T) { testhelpers.NewErrorTestServer(t, reg) public, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") t.Run("does redirect to default on authenticated request", func(t *testing.T) { body, _ := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", public.URL+recovery.PublicRecoveryInitPath, nil)) @@ -92,7 +92,7 @@ func TestRecoveryHandler(t *testing.T) { } } - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/recovery.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/recovery.schema.json") t.Run("daemon=admin", func(t *testing.T) { regTS := newRecoveryTS(t, admin.URL, nil) diff --git a/selfservice/flow/recovery/persistence.go b/selfservice/flow/recovery/persistence.go index 717322e5e8ad..153d71ae64b8 100644 --- a/selfservice/flow/recovery/persistence.go +++ b/selfservice/flow/recovery/persistence.go @@ -34,7 +34,7 @@ func TestRequestPersister(p interface { RequestPersister identity.PrivilegedPool }) func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") var clearids = func(r *Request) { r.ID = uuid.UUID{} diff --git a/selfservice/flow/recovery/stub/identity.schema.json b/selfservice/flow/recovery/stub/identity.schema.json index 04ed04e224a0..c465b281705b 100644 --- a/selfservice/flow/recovery/stub/identity.schema.json +++ b/selfservice/flow/recovery/stub/identity.schema.json @@ -4,38 +4,43 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } } }, - "verification": { - "via": "email" + "stringy": { + "type": "string" }, - "recovery": { - "via": "email" + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 } } - }, - "stringy": { - "type": "string" - }, - "numby": { - "type": "number" - }, - "booly": { - "type": "boolean" - }, - "should_big_number": { - "type": "number", - "minimum": 1200 - }, - "should_long_string": { - "type": "string", - "minLength": 25 } } } diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index ab769f284297..b4f787f630d5 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -34,7 +34,7 @@ func TestHandlerRedirectOnAuthenticated(t *testing.T) { ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) testhelpers.NewRedirTS(t, "already authenticated") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") t.Run("does redirect to default on authenticated request", func(t *testing.T) { body, _ := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+registration.BrowserRegistrationPath, nil)) @@ -98,7 +98,7 @@ func TestRegistrationHandler(t *testing.T) { defer errTS.Close() viper.Set(configuration.ViperKeyPublicBaseURL, public.URL) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") viper.Set(configuration.ViperKeySelfServiceErrorUI, errTS.URL) viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), map[string]interface{}{ "enabled": true}) diff --git a/selfservice/flow/registration/hook_test.go b/selfservice/flow/registration/hook_test.go index 13ba6cd45ecc..4cd0dce9dc5b 100644 --- a/selfservice/flow/registration/hook_test.go +++ b/selfservice/flow/registration/hook_test.go @@ -30,7 +30,7 @@ func TestRegistrationExecutor(t *testing.T) { } { t.Run("strategy="+strategy, func(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") newServer := func(t *testing.T, i *identity.Identity) *httptest.Server { diff --git a/selfservice/flow/registration/stub/fake-session.schema.json b/selfservice/flow/registration/stub/fake-session.schema.json index 558106d35900..bbcc9f405c56 100644 --- a/selfservice/flow/registration/stub/fake-session.schema.json +++ b/selfservice/flow/registration/stub/fake-session.schema.json @@ -3,5 +3,9 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", - "properties": {} + "properties": { + "traits": { + "type": "object" + } + } } diff --git a/selfservice/flow/registration/stub/identity.schema.json b/selfservice/flow/registration/stub/identity.schema.json index 22965676cdc0..10f59c41f911 100644 --- a/selfservice/flow/registration/stub/identity.schema.json +++ b/selfservice/flow/registration/stub/identity.schema.json @@ -4,35 +4,41 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } } }, - "verification": { - "via": "email" + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 } + } - }, - "stringy": { - "type": "string" - }, - "numby": { - "type": "number" - }, - "booly": { - "type": "boolean" - }, - "should_big_number": { - "type": "number", - "minimum": 1200 - }, - "should_long_string": { - "type": "string", - "minLength": 25 } } } diff --git a/selfservice/flow/registration/stub/login.schema.json b/selfservice/flow/registration/stub/login.schema.json index ec435cd1a957..d358bd7ea1cd 100644 --- a/selfservice/flow/registration/stub/login.schema.json +++ b/selfservice/flow/registration/stub/login.schema.json @@ -4,8 +4,14 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/registration/stub/registration.schema.json b/selfservice/flow/registration/stub/registration.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/registration/stub/registration.schema.json +++ b/selfservice/flow/registration/stub/registration.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/registration/stub/updated.schema.json b/selfservice/flow/registration/stub/updated.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/flow/registration/stub/updated.schema.json +++ b/selfservice/flow/registration/stub/updated.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/flow/settings/extension.go b/selfservice/flow/settings/extension.go deleted file mode 100644 index c95b9c953ec7..000000000000 --- a/selfservice/flow/settings/extension.go +++ /dev/null @@ -1,58 +0,0 @@ -package settings - -import ( - "bytes" - "encoding/json" - - "github.com/pkg/errors" - "github.com/tidwall/gjson" - - "github.com/ory/kratos/selfservice/form" - - "github.com/ory/jsonschema/v3" - "github.com/ory/x/jsonschemax" -) - -const ( - extensionName = "disableIdentifiersExtension" - extensionKey = "ory.sh/kratos" -) - -type disableIdentifiersExtConfig struct { - disabled bool -} - -func registerNewDisableIdentifiersExtension(compiler *jsonschema.Compiler) { - compiler.Extensions[extensionName] = jsonschema.Extension{ - // as we just use the compiler to check whether there the flag *.ory\.sh/kratos.credentials.password.identifier - // set we don't really need a meta schema - Meta: nil, - Compile: compile, - } -} - -// this function adds the custom property IsDisabledField to the path so that we can use it to disable form fields etc. -func (ec *disableIdentifiersExtConfig) EnhancePath(_ jsonschemax.Path) map[string]interface{} { - // if this path is an identifier the form field should be disabled - if ec.disabled { - return map[string]interface{}{ - form.DisableFormField: true, - } - } - return nil -} - -func compile(_ jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) { - if raw, ok := m[extensionKey]; ok { - var b bytes.Buffer - if err := json.NewEncoder(&b).Encode(raw); err != nil { - return nil, errors.WithStack(err) - } - - var e disableIdentifiersExtConfig - e.disabled = gjson.GetBytes(b.Bytes(), "credentials.password.identifier").Bool() - - return &e, nil - } - return nil, nil -} diff --git a/selfservice/flow/settings/extension_test.go b/selfservice/flow/settings/extension_test.go deleted file mode 100644 index 3f8b1ca4f634..000000000000 --- a/selfservice/flow/settings/extension_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package settings - -import ( - "fmt" - "testing" - - "github.com/ory/kratos/selfservice/form" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ory/jsonschema/v3" - "github.com/ory/x/jsonschemax" -) - -func TestDisableIdentifiersExtension(t *testing.T) { - for k, tc := range []struct { - schema string - expectDisabledPathNames []string - }{ - { - schema: "file://./stub/identity.schema.json", - expectDisabledPathNames: []string{"email"}, - }, - } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - c := jsonschema.NewCompiler() - registerNewDisableIdentifiersExtension(c) - paths, err := jsonschemax.ListPaths(tc.schema, c) - require.NoError(t, err) - - t.Logf("%+v", paths) - var disabledPathNames []string - for _, p := range paths { - if disabled, ok := p.CustomProperties[form.DisableFormField]; ok { - if d, ok := disabled.(bool); ok && d { - disabledPathNames = append(disabledPathNames, p.Name) - } - } - } - - assert.Equal(t, tc.expectDisabledPathNames, disabledPathNames) - }) - } -} diff --git a/selfservice/flow/settings/handler_test.go b/selfservice/flow/settings/handler_test.go index cafb8dbcdc0c..1af23cf7f872 100644 --- a/selfservice/flow/settings/handler_test.go +++ b/selfservice/flow/settings/handler_test.go @@ -32,7 +32,7 @@ func init() { func TestHandler(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") testhelpers.StrategyEnable(identity.CredentialsTypePassword.String(), true) testhelpers.StrategyEnable(settings.StrategyProfile, true) diff --git a/selfservice/flow/settings/hook_test.go b/selfservice/flow/settings/hook_test.go index 3a5b5075e436..12df1f953d79 100644 --- a/selfservice/flow/settings/hook_test.go +++ b/selfservice/flow/settings/hook_test.go @@ -31,7 +31,7 @@ func TestSettingsExecutor(t *testing.T) { } { t.Run("strategy="+strategy, func(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") reg.WithHooks(map[string]func(configuration.SelfServiceHook) interface{}{ diff --git a/selfservice/flow/settings/persistence.go b/selfservice/flow/settings/persistence.go index a74cf5989b71..dca97ad2e0eb 100644 --- a/selfservice/flow/settings/persistence.go +++ b/selfservice/flow/settings/persistence.go @@ -33,7 +33,7 @@ func TestRequestPersister(p interface { RequestPersister identity.PrivilegedPool }) func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") var clearids = func(r *Request) { r.ID = uuid.UUID{} @@ -87,7 +87,7 @@ func TestRequestPersister(p interface { assert.EqualValues(t, expected.RequestURL, actual.RequestURL) assert.EqualValues(t, expected.Identity.ID, actual.Identity.ID) assert.EqualValues(t, expected.Identity.Traits, actual.Identity.Traits) - assert.EqualValues(t, expected.Identity.TraitsSchemaID, actual.Identity.TraitsSchemaID) + assert.EqualValues(t, expected.Identity.SchemaID, actual.Identity.SchemaID) assert.Empty(t, actual.Identity.Credentials) }) diff --git a/selfservice/flow/settings/stub/identity.schema.json b/selfservice/flow/settings/stub/identity.schema.json index 22965676cdc0..cfcb8db01ca6 100644 --- a/selfservice/flow/settings/stub/identity.schema.json +++ b/selfservice/flow/settings/stub/identity.schema.json @@ -4,35 +4,40 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits":{ + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } } }, - "verification": { - "via": "email" + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 } } - }, - "stringy": { - "type": "string" - }, - "numby": { - "type": "number" - }, - "booly": { - "type": "boolean" - }, - "should_big_number": { - "type": "number", - "minimum": 1200 - }, - "should_long_string": { - "type": "string", - "minLength": 25 } } } diff --git a/selfservice/flow/verify/handler_test.go b/selfservice/flow/verify/handler_test.go index b84565a13ea7..c71aacb67dda 100644 --- a/selfservice/flow/verify/handler_test.go +++ b/selfservice/flow/verify/handler_test.go @@ -62,7 +62,7 @@ func TestHandler(t *testing.T) { defer errTS.Close() viper.Set(configuration.ViperKeyPublicBaseURL, publicTS.URL) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/extension/schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/extension/schema.json") viper.Set(configuration.ViperKeySelfServiceErrorUI, errTS.URL) viper.Set(configuration.ViperKeySelfServiceVerificationUI, verifyTS.URL) viper.Set(configuration.ViperKeySelfServiceVerificationBrowserDefaultReturnTo, redirTS.URL) diff --git a/selfservice/flow/verify/persistence.go b/selfservice/flow/verify/persistence.go index 80cdefacc9de..3851b2de772f 100644 --- a/selfservice/flow/verify/persistence.go +++ b/selfservice/flow/verify/persistence.go @@ -35,7 +35,7 @@ func TestPersister(p interface { Persister identity.PrivilegedPool }) func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") return func(t *testing.T) { t.Run("suite=request", func(t *testing.T) { t.Run("case=should error when the verify does not exist", func(t *testing.T) { diff --git a/selfservice/flow/verify/sender_test.go b/selfservice/flow/verify/sender_test.go index 685abcb11564..dd6a94258b8a 100644 --- a/selfservice/flow/verify/sender_test.go +++ b/selfservice/flow/verify/sender_test.go @@ -18,7 +18,7 @@ import ( func TestManager(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/extension/schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/extension/schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh/") viper.Set(configuration.ViperKeyCourierSMTPURL, "smtp://foo@bar@dev.null/") diff --git a/selfservice/flow/verify/stub/extension/schema.json b/selfservice/flow/verify/stub/extension/schema.json index 9906957f32af..4dc2cdbb5940 100644 --- a/selfservice/flow/verify/stub/extension/schema.json +++ b/selfservice/flow/verify/stub/extension/schema.json @@ -1,22 +1,29 @@ { + "$id": "https://example.com/registration.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "ory.sh/kratos": { - "verification": { - "via": "email" + "traits": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "ory.sh/kratos": { + "verification": { + "via": "email" + } + } + } + }, + "username": { + "type": "string", + "ory.sh/kratos": { + "verification": { + "via": "email" + } } - } - } - }, - "username": { - "type": "string", - "ory.sh/kratos": { - "verification": { - "via": "email" } } } diff --git a/selfservice/form/container.go b/selfservice/form/container.go index 3075cb48f67c..168a0d64ef00 100644 --- a/selfservice/form/container.go +++ b/selfservice/form/container.go @@ -58,5 +58,5 @@ type MessageResetter interface { } type FieldSorter interface { - SortFields(schemaRef string, prefix string) error + SortFields(schemaRef string) error } diff --git a/selfservice/form/fields.go b/selfservice/form/fields.go index 4b400c5d1d68..2424b238849e 100644 --- a/selfservice/form/fields.go +++ b/selfservice/form/fields.go @@ -65,7 +65,10 @@ func (ff *Fields) sortBySchema(schemaRef, prefix string) (func(i, j int) bool, e "password", } for _, k := range schemaKeys { - keysInOrder = append(keysInOrder, fmt.Sprintf("%s.%s", prefix, k)) + if prefix != "" { + k = fmt.Sprintf("%s.%s", prefix, k) + } + keysInOrder = append(keysInOrder, k) } getKeyPosition := func(name string) int { diff --git a/selfservice/form/fields_test.go b/selfservice/form/fields_test.go index 8412eba3a892..3476295aae6c 100644 --- a/selfservice/form/fields_test.go +++ b/selfservice/form/fields_test.go @@ -16,7 +16,7 @@ import ( ) func TestFieldFromPath(t *testing.T) { - t.Run("all properties are properly transfered", func(t *testing.T) { + t.Run("all properties are properly transferred", func(t *testing.T) { schema, err := ioutil.ReadFile("./stub/all_formats.schema.json") require.NoError(t, err) diff --git a/selfservice/form/html_form.go b/selfservice/form/html_form.go index 4a4c341a8b07..106809bbf9ef 100644 --- a/selfservice/form/html_form.go +++ b/selfservice/form/html_form.go @@ -109,8 +109,8 @@ func NewHTMLFormFromJSONSchema(action, jsonSchemaRef, prefix string, compiler *j return c, nil } -func (c *HTMLForm) SortFields(schemaRef, prefix string) error { - sortFunc, err := c.Fields.sortBySchema(schemaRef, prefix) +func (c *HTMLForm) SortFields(schemaRef string) error { + sortFunc, err := c.Fields.sortBySchema(schemaRef, "") if err != nil { return err } diff --git a/selfservice/form/html_form_test.go b/selfservice/form/html_form_test.go index e78d79d15773..aa43b9ec0887 100644 --- a/selfservice/form/html_form_test.go +++ b/selfservice/form/html_form_test.go @@ -304,4 +304,25 @@ func TestContainer(t *testing.T) { assert.Empty(t, c.getField("2").Messages) assert.Empty(t, c.getField("2").Value) }) + + t.Run("method=SortFields", func(t *testing.T) { + // use a schema compiler that disables identifiers + schemaCompiler := jsonschema.NewCompiler() + schemaPath := "stub/identity.schema.json" + + f, err := NewHTMLFormFromJSONSchema("/foo", schemaPath, "", schemaCompiler) + require.NoError(t, err) + + f.SetValuesFromJSON(json.RawMessage(`{}`), "traits") + f.SetCSRF("csrf_token") + + require.NoError(t, f.SortFields(schemaPath)) + + var names []string + for _, f := range f.Fields { + names = append(names, f.Name) + } + + assert.EqualValues(t, []string{"csrf_token", "traits.email", "traits.stringy", "traits.numby", "traits.booly", "traits.should_big_number", "traits.should_long_string"}, names, "%+v", f.Fields) + }) } diff --git a/selfservice/form/stub/identity.schema.json b/selfservice/form/stub/identity.schema.json new file mode 100644 index 000000000000..6bdf636f9a6c --- /dev/null +++ b/selfservice/form/stub/identity.schema.json @@ -0,0 +1,43 @@ +{ + "$id": "https://example.com/registration.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } + } + }, + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 + } + } + } + } +} diff --git a/selfservice/hook/session_destroyer_test.go b/selfservice/hook/session_destroyer_test.go index 75aa20a3026b..f5f0bd77ddd7 100644 --- a/selfservice/hook/session_destroyer_test.go +++ b/selfservice/hook/session_destroyer_test.go @@ -30,7 +30,7 @@ func TestSessionDestroyer(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) viper.Set(configuration.ViperKeyPublicBaseURL, "http://localhost/") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/stub.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/stub.schema.json") h := hook.NewSessionIssuer(reg) diff --git a/selfservice/hook/session_issuer_test.go b/selfservice/hook/session_issuer_test.go index 1922a520cd1b..2cef447e0200 100644 --- a/selfservice/hook/session_issuer_test.go +++ b/selfservice/hook/session_issuer_test.go @@ -23,7 +23,7 @@ import ( func TestSessionIssuer(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) viper.Set(configuration.ViperKeyPublicBaseURL, "http://localhost/") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/stub.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/stub.schema.json") var r http.Request h := hook.NewSessionIssuer(reg) diff --git a/selfservice/hook/stub/stub.schema.json b/selfservice/hook/stub/stub.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/hook/stub/stub.schema.json +++ b/selfservice/hook/stub/stub.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/hook/stub/verify.schema.json b/selfservice/hook/stub/verify.schema.json index 94238ada84b9..f71a32a088d4 100644 --- a/selfservice/hook/stub/verify.schema.json +++ b/selfservice/hook/stub/verify.schema.json @@ -4,13 +4,18 @@ "title": "Person", "type": "object", "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "ory.sh/kratos": { - "verification": { - "via": "email" + "traits": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "ory.sh/kratos": { + "verification": { + "via": "email" + } + } } } } diff --git a/selfservice/hook/verification_test.go b/selfservice/hook/verification_test.go index 6afd78f17327..597089e88f17 100644 --- a/selfservice/hook/verification_test.go +++ b/selfservice/hook/verification_test.go @@ -32,7 +32,7 @@ func TestVerifier(t *testing.T) { } { t.Run("name="+k, func(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/verify.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/verify.schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh/") viper.Set(configuration.ViperKeyCourierSMTPURL, "smtp://foo@bar@dev.null/") diff --git a/selfservice/strategy/oidc/form.go b/selfservice/strategy/oidc/form.go index 6355157f1cd6..edd23931a227 100644 --- a/selfservice/strategy/oidc/form.go +++ b/selfservice/strategy/oidc/form.go @@ -15,7 +15,7 @@ import ( ) func decoderRegistration(ref string) (decoderx.HTTPDecoderOption, error) { - raw, err := sjson.SetBytes([]byte(registrationFormPayloadSchema), "properties.traits.$ref", ref) + raw, err := sjson.SetBytes([]byte(registrationFormPayloadSchema), "properties.traits.$ref", ref+"#/properties/traits") if err != nil { return nil, errors.WithStack(err) } diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index de935b1157a0..dabd0f01edb9 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -437,7 +437,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, rid uuid. method.Config.ResetMessages() method.Config.SetCSRF(s.d.GenerateCSRFToken(r)) - if errSec := method.Config.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String(), "traits"); errSec != nil { + if errSec := method.Config.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String()); errSec != nil { s.d.RegistrationRequestErrorHandler().HandleRegistrationError(w, r, s.ID(), rr, errors.Wrap(err, errSec.Error())) return } diff --git a/selfservice/strategy/oidc/strategy_settings_test.go b/selfservice/strategy/oidc/strategy_settings_test.go index 54c5de32ddba..a35eb2ce5300 100644 --- a/selfservice/strategy/oidc/strategy_settings_test.go +++ b/selfservice/strategy/oidc/strategy_settings_test.go @@ -66,21 +66,21 @@ func TestSettingsStrategy(t *testing.T) { newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "github", "github"), ) testhelpers.InitKratosServers(t, reg, publicTS, adminTS) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/settings.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/settings.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/kratos") // Make test data for this test run unique testID := x.NewUUID().String() users := map[string]*identity.Identity{ "password": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"john` + testID + `@doe.com"}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + SchemaID: configuration.DefaultIdentityTraitsSchemaID, Credentials: map[identity.CredentialsType]identity.Credentials{ "password": {Type: "password", Identifiers: []string{"john+" + testID + "@doe.com"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"$argon2id$iammocked...."}`)}}, }, "oryer": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+` + testID + `@ory.sh"}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + SchemaID: configuration.DefaultIdentityTraitsSchemaID, Credentials: map[identity.CredentialsType]identity.Credentials{ identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+" + testID}, @@ -91,7 +91,7 @@ func TestSettingsStrategy(t *testing.T) { identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+github+" + testID, "github:hackerman+github+" + testID}, Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+github+` + testID + `"},{"provider":"github","subject":"hackerman+github+` + testID + `"}]}`)}}, - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + SchemaID: configuration.DefaultIdentityTraitsSchemaID, }, "multiuser": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+multiuser+` + testID + `@ory.sh"}`), Credentials: map[identity.CredentialsType]identity.Credentials{ @@ -101,7 +101,7 @@ func TestSettingsStrategy(t *testing.T) { identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+multiuser+" + testID, "google:hackerman+multiuser+" + testID}, Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+multiuser+` + testID + `"},{"provider":"google","subject":"hackerman+multiuser+` + testID + `"}]}`)}}, - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + SchemaID: configuration.DefaultIdentityTraitsSchemaID, }, } agents := testhelpers.AddAndLoginIdentities(t, reg, publicTS, users) @@ -182,7 +182,7 @@ func TestSettingsStrategy(t *testing.T) { assert.NotEmpty(t, req.IssuedAt) assert.EqualValues(t, users["password"].ID, req.Identity.ID) assert.EqualValues(t, users["password"].Traits, req.Identity.Traits) - assert.EqualValues(t, users["password"].TraitsSchemaID, req.Identity.TraitsSchemaID) + assert.EqualValues(t, users["password"].SchemaID, req.Identity.SchemaID) assert.EqualValues(t, req.ID.String(), rs.Payload.ID) assert.EqualValues(t, req.RequestURL, *rs.Payload.RequestURL) @@ -526,7 +526,7 @@ func TestPopulateSettingsMethod(t *testing.T) { nreg := func(t *testing.T, conf *oidc.ConfigurationCollection) *driver.RegistryDefault { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://stub/registration.schema.json") viper.Set(configuration.ViperKeyPublicBaseURL, "https://www.ory.sh/") // Enabled per default: diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 938a824efe1e..828eb274b234 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -66,7 +66,7 @@ func TestStrategy(t *testing.T) { }, ) testhelpers.InitKratosServers(t, reg, ts, tsA) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") viper.Set(configuration.HookStrategyKey(configuration.ViperKeySelfServiceRegistrationAfter, identity.CredentialsTypeOIDC.String()), []configuration.SelfServiceHook{{Name: "session"}}) diff --git a/selfservice/strategy/oidc/stub/extension/schema.json b/selfservice/strategy/oidc/stub/extension/schema.json index 3711981067eb..1d57ae2e97e2 100644 --- a/selfservice/strategy/oidc/stub/extension/schema.json +++ b/selfservice/strategy/oidc/stub/extension/schema.json @@ -4,41 +4,46 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "ory.sh/kratos": { - "mappings": { - "identity": { - "traits": [ - { - "path": "email" + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "mappings": { + "identity": { + "traits": [ + { + "path": "email" + } + ] } - ] + } } - } - } - }, - "names": { - "type": "array", - "items": { - "type": "string", - "ory.sh/kratos": { - "mappings": { - "identity": { - "traits": [ - { - "path": "names.-1" + }, + "names": { + "type": "array", + "items": { + "type": "string", + "ory.sh/kratos": { + "mappings": { + "identity": { + "traits": [ + { + "path": "names.-1" + } + ] } - ] + } } } } - } + }, + "required": [ + "email" + ], + "additionalProperties": false } - }, - "required": [ - "email" - ], - "additionalProperties": false + } } diff --git a/selfservice/strategy/oidc/stub/form-merge.schema.json b/selfservice/strategy/oidc/stub/form-merge.schema.json deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/selfservice/strategy/oidc/stub/merge/1.schema.json b/selfservice/strategy/oidc/stub/merge/1.schema.json index cce0d337d9ca..d31ab711af39 100644 --- a/selfservice/strategy/oidc/stub/merge/1.schema.json +++ b/selfservice/strategy/oidc/stub/merge/1.schema.json @@ -3,17 +3,22 @@ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { - "foo": { - "type": "string" - }, - "baz": { - "type": "string" - }, - "bool": { - "type": "boolean" - }, - "opv": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "foo": { + "type": "string" + }, + "baz": { + "type": "string" + }, + "bool": { + "type": "boolean" + }, + "opv": { + "type": "string" + } + } } } -} \ No newline at end of file +} diff --git a/selfservice/strategy/oidc/stub/registration.schema.json b/selfservice/strategy/oidc/stub/registration.schema.json index 22afdb439ded..c6f498be9f48 100644 --- a/selfservice/strategy/oidc/stub/registration.schema.json +++ b/selfservice/strategy/oidc/stub/registration.schema.json @@ -4,24 +4,30 @@ "title": "Person", "type": "object", "properties": { - "subject": { - "format": "email", - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "subject": { + "format": "email", + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "name": { + "type": "string", + "minLength": 2 } - } - }, - "name": { - "type": "string", - "minLength": 2 + + }, + "required": [ + "subject" + ] } }, - "required": [ - "subject" - ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/selfservice/strategy/oidc/stub/settings.schema.json b/selfservice/strategy/oidc/stub/settings.schema.json index e1883cc9e4e0..9d0752b8dc87 100644 --- a/selfservice/strategy/oidc/stub/settings.schema.json +++ b/selfservice/strategy/oidc/stub/settings.schema.json @@ -4,24 +4,29 @@ "title": "Person", "type": "object", "properties": { - "email": { - "format": "email", - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "format": "email", + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "name": { + "type": "string", + "minLength": 2 } - } - }, - "name": { - "type": "string", - "minLength": 2 + }, + "required": [ + "email" + ] } }, - "required": [ - "email" - ], "additionalProperties": false } diff --git a/selfservice/strategy/password/login_test.go b/selfservice/strategy/password/login_test.go index 1ecfb720d920..7aa953dbab4b 100644 --- a/selfservice/strategy/password/login_test.go +++ b/selfservice/strategy/password/login_test.go @@ -88,7 +88,7 @@ func TestLoginNew(t *testing.T) { viper.Set(configuration.ViperKeySelfServiceErrorUI, errTs.URL+"/error-ts") viper.Set(configuration.ViperKeySelfServiceLoginUI, uiTs.URL+"/login-ts") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/login.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/login.schema.json") viper.Set(configuration.ViperKeySecretsDefault, []string{"not-a-secure-session-key"}) mr := func(t *testing.T, payload string, requestID string, c *http.Client) (*http.Response, []byte) { diff --git a/selfservice/strategy/password/registration.go b/selfservice/strategy/password/registration.go index 3187ee19155d..dd0a18c9fe46 100644 --- a/selfservice/strategy/password/registration.go +++ b/selfservice/strategy/password/registration.go @@ -70,7 +70,7 @@ func (s *Strategy) handleRegistrationError(w http.ResponseWriter, r *http.Reques method.Config.SetCSRF(s.d.GenerateCSRFToken(r)) rr.Methods[identity.CredentialsTypePassword] = method - if errSec := method.Config.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String(), "traits"); errSec != nil { + if errSec := method.Config.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String()); errSec != nil { s.d.RegistrationRequestErrorHandler().HandleRegistrationError(w, r, identity.CredentialsTypePassword, rr, errors.Wrap(err, errSec.Error())) return } @@ -81,7 +81,7 @@ func (s *Strategy) handleRegistrationError(w http.ResponseWriter, r *http.Reques } func (s *Strategy) decoderRegistration() (decoderx.HTTPDecoderOption, error) { - raw, err := sjson.SetBytes([]byte(registrationFormPayloadSchema), "properties.traits.$ref", s.c.DefaultIdentityTraitsSchemaURL().String()) + raw, err := sjson.SetBytes([]byte(registrationFormPayloadSchema), "properties.traits.$ref", s.c.DefaultIdentityTraitsSchemaURL().String()+"#/properties/traits") if err != nil { return nil, errors.WithStack(err) } @@ -196,7 +196,7 @@ func (s *Strategy) PopulateRegistrationMethod(r *http.Request, sr *registration. url.Values{"request": {sr.ID.String()}}, ) - htmlf, err := form.NewHTMLFormFromJSONSchema(action.String(), s.c.DefaultIdentityTraitsSchemaURL().String(), "traits", nil) + htmlf, err := form.NewHTMLFormFromJSONSchema(action.String(), s.c.DefaultIdentityTraitsSchemaURL().String(), "", nil) if err != nil { return err } @@ -205,7 +205,7 @@ func (s *Strategy) PopulateRegistrationMethod(r *http.Request, sr *registration. htmlf.SetCSRF(s.d.GenerateCSRFToken(r)) htmlf.SetField(form.Field{Name: "password", Type: "password", Required: true}) - if err := htmlf.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String(), "traits"); err != nil { + if err := htmlf.SortFields(s.c.DefaultIdentityTraitsSchemaURL().String()); err != nil { return err } diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index 25fc490601fb..bfc3a6b44ee5 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -81,7 +81,7 @@ func TestRegistration(t *testing.T) { viper.Set(configuration.ViperKeyPublicBaseURL, ts.URL) viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, returnTs.URL+"/default-return-to") viper.Set(configuration.ViperKeySelfServiceRegistrationAfter+"."+configuration.DefaultBrowserReturnURL, returnTs.URL+"/return-ts") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") var newRegistrationRequest = func(t *testing.T, exp time.Duration) *registration.Request { rr := ®istration.Request{ @@ -179,7 +179,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should fail because schema did not specify an identifier", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/missing-identifier.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/missing-identifier.schema.json") rr := newRegistrationRequest(t, time.Minute) body, res := makeRequest(t, rr.ID, url.Values{ "traits.username": {"registration-identifier-6"}, @@ -193,7 +193,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should fail because schema does not exist", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/i-do-not-exist.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/i-do-not-exist.schema.json") rr := newRegistrationRequest(t, time.Minute) body, res := makeRequest(t, rr.ID, url.Values{ "traits.username": {"registration-identifier-7"}, @@ -207,7 +207,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should pass and set up a session", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") viper.Set( configuration.HookStrategyKey(configuration.ViperKeySelfServiceRegistrationAfter, identity.CredentialsTypePassword.String()), []configuration.SelfServiceHook{{Name: "session"}}) @@ -223,7 +223,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should fail to register the same user again", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") rr := newRegistrationRequest(t, time.Minute) body, res := makeRequest(t, rr.ID, url.Values{ "traits.username": {"registration-identifier-8"}, @@ -235,7 +235,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should return an error because not passing validation and reset previous errors and values", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/registration.schema.json") rr := ®istration.Request{ ID: x.NewUUID(), @@ -280,7 +280,7 @@ func TestRegistration(t *testing.T) { }) t.Run("case=should work even if password is just numbers", func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://stub/registration.schema.json") rr := newRegistrationRequest(t, time.Minute) body, res := makeRequest(t, rr.ID, url.Values{ "traits.username": {"registration-identifier-10"}, @@ -312,7 +312,7 @@ func TestRegistration(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) viper.Set(configuration.ViperKeyPublicBaseURL, urlx.ParseOrPanic("https://foo/")) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://stub/registration.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://stub/registration.schema.json") viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), map[string]interface{}{ "enabled": true}) diff --git a/selfservice/strategy/password/settings_test.go b/selfservice/strategy/password/settings_test.go index 35b6cbb91558..e5ee6c2c1545 100644 --- a/selfservice/strategy/password/settings_test.go +++ b/selfservice/strategy/password/settings_test.go @@ -30,7 +30,7 @@ func init() { func TestSettings(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/profile.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/profile.schema.json") testhelpers.StrategyEnable(identity.CredentialsTypePassword.String(), true) testhelpers.StrategyEnable(settings.StrategyProfile, true) @@ -43,14 +43,14 @@ func TestSettings(t *testing.T) { Credentials: map[identity.CredentialsType]identity.Credentials{ "password": {Type: "password", Identifiers: []string{"john@doe.com"}, Config: []byte(`{"hashed_password":"foo"}`)}, }, - Traits: identity.Traits(`{"email":"john@doe.com"}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + Traits: identity.Traits(`{"email":"john@doe.com"}`), + SchemaID: configuration.DefaultIdentityTraitsSchemaID, } secondaryIdentity := &identity.Identity{ - ID: x.NewUUID(), - Credentials: map[identity.CredentialsType]identity.Credentials{}, - Traits: identity.Traits(`{}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + ID: x.NewUUID(), + Credentials: map[identity.CredentialsType]identity.Credentials{}, + Traits: identity.Traits(`{}`), + SchemaID: configuration.DefaultIdentityTraitsSchemaID, } publicTS, adminTS, clients := testhelpers.NewSettingsAPIServer(t, reg, map[string]*identity.Identity{ "primary": primaryIdentity, "secondary": secondaryIdentity}) diff --git a/selfservice/strategy/password/stub/login.schema.json b/selfservice/strategy/password/stub/login.schema.json index a91b7d312f8f..82f85811a16a 100644 --- a/selfservice/strategy/password/stub/login.schema.json +++ b/selfservice/strategy/password/stub/login.schema.json @@ -2,5 +2,10 @@ "$id": "https://example.com/person.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", - "type": "object" -} \ No newline at end of file + "type": "object", + "properties": { + "traits": { + "type": "object" + } + } +} diff --git a/selfservice/strategy/password/stub/missing-identifier.schema.json b/selfservice/strategy/password/stub/missing-identifier.schema.json index 684e4ccb35b0..eef4e8157756 100644 --- a/selfservice/strategy/password/stub/missing-identifier.schema.json +++ b/selfservice/strategy/password/stub/missing-identifier.schema.json @@ -4,17 +4,22 @@ "title": "Person", "type": "object", "properties": { - "foobar": { - "type": "string", - "minLength": 2 - }, - "username": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "foobar": { + "type": "string", + "minLength": 2 + }, + "username": { + "type": "string" + } + }, + "required": [ + "foobar", + "username" + ] } }, - "required": [ - "foobar", - "username" - ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/selfservice/strategy/password/stub/profile.schema.json b/selfservice/strategy/password/stub/profile.schema.json index ea93f0bfe96d..f3c1a22b1fdc 100644 --- a/selfservice/strategy/password/stub/profile.schema.json +++ b/selfservice/strategy/password/stub/profile.schema.json @@ -4,6 +4,9 @@ "title": "Person", "type": "object", "properties": { + "traits": { + "type": "object", + "properties": { "email": { "type": "string", "ory.sh/kratos": { @@ -14,6 +17,8 @@ } } } + } + } }, "additionalProperties": false } diff --git a/selfservice/strategy/password/stub/registration.schema.json b/selfservice/strategy/password/stub/registration.schema.json index 176e17970b3a..2867d732c759 100644 --- a/selfservice/strategy/password/stub/registration.schema.json +++ b/selfservice/strategy/password/stub/registration.schema.json @@ -4,24 +4,29 @@ "title": "Person", "type": "object", "properties": { - "foobar": { - "type": "string", - "minLength": 2 - }, - "username": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "foobar": { + "type": "string", + "minLength": 2 + }, + "username": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } - } + }, + "required": [ + "foobar", + "username" + ] } }, - "required": [ - "foobar", - "username" - ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/selfservice/strategy/profile/strategy.go b/selfservice/strategy/profile/strategy.go index 88f03c392d31..123190d926b1 100644 --- a/selfservice/strategy/profile/strategy.go +++ b/selfservice/strategy/profile/strategy.go @@ -89,7 +89,7 @@ func (s *Strategy) RegisterSettingsRoutes(public *x.RouterPublic) { } func (s *Strategy) PopulateSettingsMethod(r *http.Request, ss *session.Session, pr *settings.Request) error { - traitsSchema, err := s.c.IdentityTraitsSchemas().FindSchemaByID(ss.Identity.TraitsSchemaID) + traitsSchema, err := s.c.IdentityTraitsSchemas().FindSchemaByID(ss.Identity.SchemaID) if err != nil { return err } @@ -100,7 +100,7 @@ func (s *Strategy) PopulateSettingsMethod(r *http.Request, ss *session.Session, f, err := form.NewHTMLFormFromJSONSchema(urlx.CopyWithQuery( urlx.AppendPaths(s.c.SelfPublicURL(), PublicSettingsProfilePath), url.Values{"request": {pr.ID.String()}}, - ).String(), traitsSchema.URL, "traits", schemaCompiler) + ).String(), traitsSchema.URL, "", schemaCompiler) if err != nil { return err } @@ -108,7 +108,7 @@ func (s *Strategy) PopulateSettingsMethod(r *http.Request, ss *session.Session, f.SetValuesFromJSON(json.RawMessage(ss.Identity.Traits), "traits") f.SetCSRF(s.d.GenerateCSRFToken(r)) - if err := f.SortFields(traitsSchema.URL, "traits"); err != nil { + if err := f.SortFields(traitsSchema.URL); err != nil { return err } @@ -263,12 +263,12 @@ func (s *Strategy) hydrateForm(r *http.Request, ar *settings.Request, ss *sessio } ar.Methods[settings.StrategyProfile].Config.SetCSRF(s.d.GenerateCSRFToken(r)) - traitsSchema, err := s.c.IdentityTraitsSchemas().FindSchemaByID(ss.Identity.TraitsSchemaID) + traitsSchema, err := s.c.IdentityTraitsSchemas().FindSchemaByID(ss.Identity.SchemaID) if err != nil { return err } - if err = ar.Methods[settings.StrategyProfile].Config.SortFields(traitsSchema.URL, "traits"); err != nil { + if err = ar.Methods[settings.StrategyProfile].Config.SortFields(traitsSchema.URL); err != nil { return err } @@ -323,14 +323,14 @@ func (s *Strategy) newSettingsProfileDecoder(i *identity.Identity) (decoderx.HTT } ` - ss, err := s.d.IdentityTraitsSchemas().GetByID(i.TraitsSchemaID) + ss, err := s.d.IdentityTraitsSchemas().GetByID(i.SchemaID) if err != nil { return nil, err } raw, err := sjson.SetBytes( []byte(registrationFormPayloadSchema), "properties.traits.$ref", - ss.URL.String(), + ss.URL.String()+"#/properties/traits", ) if err != nil { return nil, errors.WithStack(err) diff --git a/selfservice/strategy/profile/strategy_test.go b/selfservice/strategy/profile/strategy_test.go index c24aea227db5..4339b10d3292 100644 --- a/selfservice/strategy/profile/strategy_test.go +++ b/selfservice/strategy/profile/strategy_test.go @@ -1,6 +1,7 @@ package profile_test import ( + "bytes" "context" "encoding/json" "fmt" @@ -42,7 +43,7 @@ func init() { func TestStrategyTraits(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") testhelpers.StrategyEnable(identity.CredentialsTypePassword.String(), true) testhelpers.StrategyEnable(settings.StrategyProfile, true) @@ -58,7 +59,7 @@ func TestStrategyTraits(t *testing.T) { "password": {Type: "password", Identifiers: []string{"john@doe.com"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}, }, Traits: identity.Traits(`{"email":"john@doe.com","stringy":"foobar","booly":false,"numby":2.5,"should_long_string":"asdfasdfasdfasdfasfdasdfasdfasdf","should_big_number":2048}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + SchemaID: configuration.DefaultIdentityTraitsSchemaID, VerifiableAddresses: []identity.VerifiableAddress{{Value: "john@doe.com", Via: identity.VerifiableAddressTypeEmail}}, } publicTS, adminTS, clients := testhelpers.NewSettingsAPIServer(t, reg, map[string]*identity.Identity{ @@ -121,7 +122,7 @@ func TestStrategyTraits(t *testing.T) { assert.NotEmpty(t, pr.Payload.Identity) assert.Equal(t, primaryIdentity.ID.String(), string(pr.Payload.Identity.ID)) assert.JSONEq(t, string(primaryIdentity.Traits), x.MustEncodeJSON(t, pr.Payload.Identity.Traits)) - assert.Equal(t, primaryIdentity.TraitsSchemaID, pointerx.StringR(pr.Payload.Identity.TraitsSchemaID)) + assert.Equal(t, primaryIdentity.SchemaID, pointerx.StringR(pr.Payload.Identity.SchemaID)) assert.Equal(t, publicTS.URL+settings.PublicPath, pointerx.StringR(pr.Payload.RequestURL)) found := false @@ -139,6 +140,9 @@ func TestStrategyTraits(t *testing.T) { } require.True(t, found) + var b bytes.Buffer + require.NoError(t, json.NewEncoder(&b).Encode(f)) + assert.EqualValues(t, &models.Form{ Action: pointerx.String(publicTS.URL + profile.PublicSettingsProfilePath + "?request=" + rid), Method: pointerx.String("POST"), @@ -150,7 +154,7 @@ func TestStrategyTraits(t *testing.T) { &models.FormField{Name: pointerx.String("traits.should_big_number"), Type: pointerx.String("number"), Value: json.Number("2048")}, &models.FormField{Name: pointerx.String("traits.should_long_string"), Type: pointerx.String("text"), Value: "asdfasdfasdfasdfasfdasdfasdfasdf"}, }, - }, f) + }, f, "%s", b.String()) }) t.Run("description=should come back with form errors if some profile data is invalid", func(t *testing.T) { diff --git a/selfservice/strategy/profile/stub/identity.schema.json b/selfservice/strategy/profile/stub/identity.schema.json index 22965676cdc0..6bdf636f9a6c 100644 --- a/selfservice/strategy/profile/stub/identity.schema.json +++ b/selfservice/strategy/profile/stub/identity.schema.json @@ -4,35 +4,40 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } } }, - "verification": { - "via": "email" + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "booly": { + "type": "boolean" + }, + "should_big_number": { + "type": "number", + "minimum": 1200 + }, + "should_long_string": { + "type": "string", + "minLength": 25 } } - }, - "stringy": { - "type": "string" - }, - "numby": { - "type": "number" - }, - "booly": { - "type": "boolean" - }, - "should_big_number": { - "type": "number", - "minimum": 1200 - }, - "should_long_string": { - "type": "string", - "minLength": 25 } } } diff --git a/selfservice/strategy/recoverytoken/persister_conformity.go b/selfservice/strategy/recoverytoken/persister_conformity.go index e4462e7e93fc..531a3693f66b 100644 --- a/selfservice/strategy/recoverytoken/persister_conformity.go +++ b/selfservice/strategy/recoverytoken/persister_conformity.go @@ -22,7 +22,7 @@ func TestPersister(p interface { recovery.RequestPersister identity.PrivilegedPool }) func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") viper.Set(configuration.ViperKeySecretsDefault, []string{"secret-a", "secret-b"}) return func(t *testing.T) { t.Run("case=should error when the recovery token does not exist", func(t *testing.T) { diff --git a/selfservice/strategy/recoverytoken/strategy_test.go b/selfservice/strategy/recoverytoken/strategy_test.go index 612c368a08df..209c4f6e19c2 100644 --- a/selfservice/strategy/recoverytoken/strategy_test.go +++ b/selfservice/strategy/recoverytoken/strategy_test.go @@ -35,13 +35,13 @@ func init() { var identityToRecover = &identity.Identity{ Credentials: map[identity.CredentialsType]identity.Credentials{ "password": {Type: "password", Identifiers: []string{"recover@ory.sh"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}}, - Traits: identity.Traits(`{"email":"recover@ory.sh"}`), - TraitsSchemaID: configuration.DefaultIdentityTraitsSchemaID, + Traits: identity.Traits(`{"email":"recover@ory.sh"}`), + SchemaID: configuration.DefaultIdentityTraitsSchemaID, } func TestStrategy(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/default.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/default.schema.json") viper.Set(configuration.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+identity.CredentialsTypePassword.String()+".enabled", true) viper.Set(configuration.ViperKeySelfServiceStrategyConfig+"."+recovery.StrategyRecoveryTokenName+".enabled", true) diff --git a/selfservice/strategy/recoverytoken/stub/default.schema.json b/selfservice/strategy/recoverytoken/stub/default.schema.json index 25c8aa1230f2..8dc923266050 100644 --- a/selfservice/strategy/recoverytoken/stub/default.schema.json +++ b/selfservice/strategy/recoverytoken/stub/default.schema.json @@ -4,19 +4,24 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } } - }, - "verification": { - "via": "email" - }, - "recovery": { - "via": "email" } } } diff --git a/selfservice/stub/identity.schema.json b/selfservice/stub/identity.schema.json index fe94126c9526..9cb780ea591b 100644 --- a/selfservice/stub/identity.schema.json +++ b/selfservice/stub/identity.schema.json @@ -4,18 +4,22 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" - }, - "email": { - "type": "string", - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + }, + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } } } } } -} diff --git a/selfservice/stub/new-form.json b/selfservice/stub/new-form.json index 7a0b1faa0409..7b6db2ab06e6 100644 --- a/selfservice/stub/new-form.json +++ b/selfservice/stub/new-form.json @@ -4,13 +4,7 @@ "title": "Person", "type": "object", "properties": { - "stringy": { - "type": "string" - }, - "numby": { - "type": "number" - }, - "objy": { + "traits": { "type": "object", "properties": { "stringy": { @@ -21,7 +15,18 @@ }, "objy": { "type": "object", - "properties": {} + "properties": { + "stringy": { + "type": "string" + }, + "numby": { + "type": "number" + }, + "objy": { + "type": "object", + "properties": {} + } + } } } } diff --git a/selfservice/stub/registration.schema.json b/selfservice/stub/registration.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/stub/registration.schema.json +++ b/selfservice/stub/registration.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/selfservice/stub/updated.schema.json b/selfservice/stub/updated.schema.json index ec435cd1a957..c7005d87ce8d 100644 --- a/selfservice/stub/updated.schema.json +++ b/selfservice/stub/updated.schema.json @@ -4,8 +4,13 @@ "title": "Person", "type": "object", "properties": { - "bar": { - "type": "string" + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } } } } diff --git a/session/persistence.go b/session/persistence.go index fc6efe31e287..7d6f3515d73a 100644 --- a/session/persistence.go +++ b/session/persistence.go @@ -39,7 +39,7 @@ func TestPersister(p interface { identity.PrivilegedPool }) func(t *testing.T) { return func(t *testing.T) { - viper.Set(configuration.ViperKeyDefaultIdentityTraitsSchemaURL, "file://./stub/identity.schema.json") + viper.Set(configuration.ViperKeyDefaultIdentitySchemaURL, "file://./stub/identity.schema.json") t.Run("case=not found", func(t *testing.T) { _, err := p.GetSession(context.Background(), x.NewUUID()) @@ -58,8 +58,8 @@ func TestPersister(p interface { actual, err := p.GetSession(context.Background(), expected.ID) require.NoError(t, err) assert.Equal(t, expected.Identity.ID, actual.Identity.ID) - assert.NotEmpty(t, actual.Identity.TraitsSchemaURL) - assert.NotEmpty(t, actual.Identity.TraitsSchemaID) + assert.NotEmpty(t, actual.Identity.SchemaURL) + assert.NotEmpty(t, actual.Identity.SchemaID) assert.Equal(t, expected.ID, actual.ID) assert.EqualValues(t, expected.ExpiresAt.Unix(), actual.ExpiresAt.Unix()) assert.Equal(t, expected.AuthenticatedAt.Unix(), actual.AuthenticatedAt.Unix()) diff --git a/test/e2e/cypress/integration/profiles/email/login/success.spec.js b/test/e2e/cypress/integration/profiles/email/login/success.spec.js index 186371cfedd1..00656730ce79 100644 --- a/test/e2e/cypress/integration/profiles/email/login/success.spec.js +++ b/test/e2e/cypress/integration/profiles/email/login/success.spec.js @@ -21,8 +21,8 @@ context('Login', () => { cy.session().should((session) => { const { identity } = session expect(identity.id).to.not.be.empty - expect(identity.traits_schema_id).to.equal('default') - expect(identity.traits_schema_url).to.equal( + expect(identity.schema_id).to.equal('default') + expect(identity.schema_url).to.equal( `${APP_URL}/.ory/kratos/public/schemas/default` ) expect(identity.traits.website).to.equal(website) diff --git a/test/e2e/cypress/integration/profiles/email/registration/success.spec.js b/test/e2e/cypress/integration/profiles/email/registration/success.spec.js index 26bfee3d588e..2da2d095d167 100644 --- a/test/e2e/cypress/integration/profiles/email/registration/success.spec.js +++ b/test/e2e/cypress/integration/profiles/email/registration/success.spec.js @@ -21,8 +21,8 @@ context('Registration', () => { const { identity } = session expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.be.undefined - expect(identity.traits_schema_id).to.equal('default') - expect(identity.traits_schema_url).to.equal( + expect(identity.schema_id).to.equal('default') + expect(identity.schema_url).to.equal( `${APP_URL}/.ory/kratos/public/schemas/default` ) expect(identity.traits.website).to.equal(website) diff --git a/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.js b/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.js index 60abfe2c4932..d9650f00c1ce 100644 --- a/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.js +++ b/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.js @@ -9,8 +9,8 @@ context('Register', () => { const shouldSession = (email) => (session) => { const { identity } = session expect(identity.id).to.not.be.empty - expect(identity.traits_schema_id).to.equal('default') - expect(identity.traits_schema_url).to.equal( + expect(identity.schema_id).to.equal('default') + expect(identity.schema_url).to.equal( `${APP_URL}/.ory/kratos/public/schemas/default` ) expect(identity.traits.website).to.equal(website) diff --git a/test/e2e/profiles/email/.kratos.yml b/test/e2e/profiles/email/.kratos.yml index d398bd95cf06..18e9cf1eace7 100644 --- a/test/e2e/profiles/email/.kratos.yml +++ b/test/e2e/profiles/email/.kratos.yml @@ -15,5 +15,4 @@ selfservice: hook: session identity: - traits: - default_schema_url: file://test/e2e/profiles/email/identity.traits.schema.json + default_schema_url: file://test/e2e/profiles/email/identity.traits.schema.json diff --git a/test/e2e/profiles/email/identity.traits.schema.json b/test/e2e/profiles/email/identity.traits.schema.json index cc9f72a2bcbe..e4dd8afb9f35 100644 --- a/test/e2e/profiles/email/identity.traits.schema.json +++ b/test/e2e/profiles/email/identity.traits.schema.json @@ -4,28 +4,33 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "website": { + "type": "string", + "format": "uri", + "minLength": 10 } - } - }, - "website": { - "type": "string", - "format": "uri", - "minLength": 10 + }, + "required": [ + "email", + "website" + ], + "additionalProperties": false } - }, - "required": [ - "email", - "website" - ], - "additionalProperties": false + } } diff --git a/test/e2e/profiles/oidc/.kratos.yml b/test/e2e/profiles/oidc/.kratos.yml index f02b43e14975..f04674256143 100644 --- a/test/e2e/profiles/oidc/.kratos.yml +++ b/test/e2e/profiles/oidc/.kratos.yml @@ -48,5 +48,4 @@ selfservice: hook: session identity: - traits: - default_schema_url: file://test/e2e/profiles/oidc/identity.traits.schema.json + default_schema_url: file://test/e2e/profiles/oidc/identity.traits.schema.json diff --git a/test/e2e/profiles/oidc/identity.traits.schema.json b/test/e2e/profiles/oidc/identity.traits.schema.json index cc9f72a2bcbe..e4dd8afb9f35 100644 --- a/test/e2e/profiles/oidc/identity.traits.schema.json +++ b/test/e2e/profiles/oidc/identity.traits.schema.json @@ -4,28 +4,33 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } } + }, + "website": { + "type": "string", + "format": "uri", + "minLength": 10 } - } - }, - "website": { - "type": "string", - "format": "uri", - "minLength": 10 + }, + "required": [ + "email", + "website" + ], + "additionalProperties": false } - }, - "required": [ - "email", - "website" - ], - "additionalProperties": false + } } diff --git a/test/e2e/profiles/recovery/.kratos.yml b/test/e2e/profiles/recovery/.kratos.yml index ba5bca8a0bb8..542228dd0dc5 100644 --- a/test/e2e/profiles/recovery/.kratos.yml +++ b/test/e2e/profiles/recovery/.kratos.yml @@ -16,5 +16,4 @@ selfservice: default_browser_return_url: http://127.0.0.1:4455/auth/login identity: - traits: - default_schema_url: file://test/e2e/profiles/recovery/identity.traits.schema.json + default_schema_url: file://test/e2e/profiles/recovery/identity.traits.schema.json diff --git a/test/e2e/profiles/recovery/identity.traits.schema.json b/test/e2e/profiles/recovery/identity.traits.schema.json index 33d2fd38a3c5..bada5a17ade5 100644 --- a/test/e2e/profiles/recovery/identity.traits.schema.json +++ b/test/e2e/profiles/recovery/identity.traits.schema.json @@ -4,25 +4,30 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "recovery": { + "via": "email" + } } - }, - "recovery": { - "via": "email" } - } + }, + "required": [ + "email" + ], + "additionalProperties": false } - }, - "required": [ - "email" - ], - "additionalProperties": false + } } diff --git a/test/e2e/profiles/verification/.kratos.yml b/test/e2e/profiles/verification/.kratos.yml index f97bc085e0ae..ffcf91b8d4a9 100644 --- a/test/e2e/profiles/verification/.kratos.yml +++ b/test/e2e/profiles/verification/.kratos.yml @@ -18,5 +18,4 @@ selfservice: default_browser_return_url: http://127.0.0.1:4455/auth/login identity: - traits: - default_schema_url: file://test/e2e/profiles/verification/identity.traits.schema.json + default_schema_url: file://test/e2e/profiles/verification/identity.traits.schema.json diff --git a/test/e2e/profiles/verification/identity.traits.schema.json b/test/e2e/profiles/verification/identity.traits.schema.json index 424efd557d93..01f65b6ccd42 100644 --- a/test/e2e/profiles/verification/identity.traits.schema.json +++ b/test/e2e/profiles/verification/identity.traits.schema.json @@ -4,25 +4,30 @@ "title": "Person", "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "title": "E-Mail", - "minLength": 3, - "ory.sh/kratos": { - "credentials": { - "password": { - "identifier": true + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } } - }, - "verification": { - "via": "email" } - } + }, + "required": [ + "email" + ], + "additionalProperties": false } - }, - "required": [ - "email" - ], - "additionalProperties": false + } } diff --git a/test/stub/identity/empty.schema.json b/test/stub/identity/empty.schema.json new file mode 100644 index 000000000000..923aa9991f82 --- /dev/null +++ b/test/stub/identity/empty.schema.json @@ -0,0 +1,10 @@ +{ + "$id": "https://example.com/stubs/identity.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "traits": { + "type": "object" + } + } +} From 261a1a18c5f9eb34bd1255398a025657bbfbc436 Mon Sep 17 00:00:00 2001 From: aeneasr Date: Tue, 7 Jul 2020 14:16:00 +0200 Subject: [PATCH 3/3] u --- go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.mod b/go.mod index 97e1062551a4..172f6e906b5f 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/ory/kratos go 1.14 -replace github.com/ory/x => ../x - require ( github.com/Masterminds/sprig/v3 v3.0.0 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect