Skip to content

Commit

Permalink
docs: refactor verification docs
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Sep 10, 2020
1 parent f0ecf51 commit 70f2789
Show file tree
Hide file tree
Showing 28 changed files with 751 additions and 241 deletions.
184 changes: 104 additions & 80 deletions docs/docs/self-service/flows/account-recovery.mdx
Expand Up @@ -39,7 +39,7 @@ The Recovery Flow can be summarized as the following state machine:
chart={`
stateDiagram
s1: Flow is initialized
s2: User Interface renders Login Flow Forms
s2: User Interface renders Recovery Flow Forms
s3: Update Recovery Flow with Error Context(s)
s4: Recovery challenge initiated (e.g. link via email)
s5: Recovery completed, user logged in
Expand All @@ -54,12 +54,29 @@ stateDiagram
`}
/>

To enable recovery flows, make the following adjustments to your ORY Kratos
configuration:

```yaml title="path/to/config/kratos.yml"
selfservice:
methods:
link:
enabled: true
flows:
recovery:
enabled: true
```

## Methods

Currently, one recovery method is supported:

- `link` method performs account recovery (also known as password reset) by
- The `link` method performs account recovery (also known as password reset) by
sending an email containing a recovery link to the user.

Methods are dis/enabled in the ORY Kratos config:
### Recovery `link` Method

The `link` method is dis/enabled in the ORY Kratos config:

```yaml title="path/to/my/kratos/config.yml"
selfservice:
Expand All @@ -69,6 +86,88 @@ selfservice:
# ...
```

There are two email types sent by this method:

<p>
<figure>
<img
alt="Recovery email sent to unknown address"
src={useBaseUrl('img/docs/mailslurper-recovery-unknown.png')}
/>
<figcaption>
If the requested email address is a known recovery address, a recovery
link is sent to that email address.
</figcaption>
</figure>
</p>

<p>
<figure>
<img
alt="Recovery email sent to unknown address"
src={useBaseUrl('img/docs/mailslurper-recovery-unknown.png')}
/>
<figcaption>
If the requested email address is a known recovery address, a recovery
link is sent to that email address.
</figcaption>
</figure>
</p>

This prevents account enumeration attacks as explained in this
[brilliant blog post by Troy Hunt](https://www.troyhunt.com/website-enumeration-insanity-how-our-personal-data-is-leaked/).

The emails are using templates that can be customised as explained in
[Customizing E-Mail Templates](../../concepts/email-sms#templates). The
template IDs are:

- Unknown email address: `recovery_invalid`
- Known email address: `recovery_valid`

You should also configure how long a session is privileged. The user will only
be able to update his/her password (or any other credential) for the specified
amount of time after clicking on the recovery link:

```yaml title="path/to/kratos/config.yml"
selfservice:
flows:
settings:
privileged_session_max_age: 15m
```

To specify that an identity's trait is a recovery email, use the following Identity JSON Schema:

```diff
{
"$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",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
+ "recovery": {
+ "via": "email"
+ }
}
}
}
"additionalProperties": false
}
}
}
```

## Initialize Recovery Flow

The first step is to initialize the Recovery Flow. This sets up Anti-CSRF tokens and more.
Expand Down Expand Up @@ -113,7 +212,7 @@ To initialize the Recovery Flow, point the Browser to
<CodeTabs items={initBrowserFlow} />

The server responds with a HTTP 302 redirect to the Recovery UI, appending the `?flow=<flow-id>` query
paremeter (see the curl example) to the URL configured here:
parameter (see the curl example) to the URL configured here:

```yaml title="path/to/config/kratos.yml"
selfservice:
Expand Down Expand Up @@ -213,85 +312,10 @@ Recovery Flow in the response payload as JSON.

#### Successful Submission

On successful submission, an email will be sent to the provided address.
On successful submission, an email will be sent to the provided address:

<CodeTabs items={getFlowMethodLinkSuccess} />

There are two email types sent by this method:

<p>
<figure>
<img
alt="Recovery email sent to unknown address"
src={useBaseUrl('img/docs/mailslurper-recovery-unknown.png')}
/>
<figcaption>
If the requested email address is a known recovery address, a recovery
link is sent to that email address.
</figcaption>
</figure>
</p>

<p>
<figure>
<img
alt="Recovery email sent to unknown address"
src={useBaseUrl('img/docs/mailslurper-recovery-unknown.png')}
/>
<figcaption>
If the requested email address is a known recovery address, a recovery
link is sent to that email address.
</figcaption>
</figure>
</p>

This prevents account enumeration attacks as explained in this
[brilliant blog post by Troy Hunt](https://www.troyhunt.com/website-enumeration-insanity-how-our-personal-data-is-leaked/).

You should also configure how long a session is privileged. The user will only
be able to update his/her password (or any other credential) for the specified
amount of time after clicking on the recovery link:

```yaml title="path/to/kratos/config.yml"
selfservice:
flows:
settings:
privileged_session_max_age: 15m
```

To specify that an identity's trait is a recovery email, use the following Identity JSON Schema:

```diff
{
"$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",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
+ "recovery": {
+ "via": "email"
+ }
}
}
}
"additionalProperties": false
}
}
}
```

## Unsuccessful Recovery

If the recovery challenge (e.g. the link in the recovery email)
Expand Down
Expand Up @@ -10,7 +10,7 @@ curl -s -v -X GET \
< HTTP/1.1 302 Found
< Cache-Control: 0
< Content-Type: text/html; charset=utf-8
< Location: http://127.0.0.1:4455/auth/recovery?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3
< Location: http://127.0.0.1:4455/recovery?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3
< Set-Cookie: csrf_token=y4Ocu6V83BapwJwbPw/pnlRHHw40DZbjq5iuDrxl0Ds=; Path=/; Domain=127.0.0.1; Max-Age=31536000; HttpOnly
<
<a href="http://127.0.0.1:4455/auth/recovery?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3">Found</a>.
<a href="http://127.0.0.1:4455/recovery?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3">Found</a>.
@@ -1,5 +1,5 @@
$ curl -H "Accept: application/json" -s \
'http://127.0.0.1:4434/self-service/recovery/flows?id=2183a80c-a190-4fde-95bd-a15aa3103930' | jq
'http://127.0.0.1:4433/self-service/recovery/flows?id=2183a80c-a190-4fde-95bd-a15aa3103930' | jq

{
"id": "2183a80c-a190-4fde-95bd-a15aa3103930",
Expand Down
@@ -1,5 +1,5 @@
$ curl -H "Accept: application/json" -s \
'http://127.0.0.1:4434/self-service/recovery/flows?id=3f1ba761-89dc-4c84-8d13-1c976ab968b2' | jq
'http://127.0.0.1:4433/self-service/recovery/flows?id=3f1ba761-89dc-4c84-8d13-1c976ab968b2' | jq

{
"id": "3f1ba761-89dc-4c84-8d13-1c976ab968b2",
Expand Down
@@ -1,15 +1,15 @@
$ curl -H "Accept: application/json" -s \
'http://127.0.0.1:4434/self-service/recovery/flows?id=73fcb010-da5c-4eb9-b329-3ed677a6897b' | jq -r '.methods.link.config'
'http://127.0.0.1:4433/self-service/verification/flows?id=ba0f508a-f2fb-435d-b5e2-0307db00d75d' | jq -r '.methods.link.config'

{
"action": "http://127.0.0.1:4433/self-service/recovery/methods/link?flow=73fcb010-da5c-4eb9-b329-3ed677a6897b",
"action": "http://127.0.0.1:4433/self-service/verification/methods/link?flow=ba0f508a-f2fb-435d-b5e2-0307db00d75d",
"method": "POST",
"fields": [
{
"name": "csrf_token",
"type": "hidden",
"required": true,
"value": "xU9NtXUeGKKmLS95hXejOTo947GsndDzStKyxUUzjX4slitKpNSPro0SJtY1M7yTZXWL/g4LK3Fdrur1a2H8ag=="
"value": "ZmifOn0KaTicicQ0NServtpnOWPD8pga5gzG028fq/4+Atwx/Yr69v/28O83GeSJB/55PTNxJHCmKW9rWX27VQ=="
},
{
"name": "email",
Expand All @@ -29,3 +29,4 @@ $ curl -H "Accept: application/json" -s \
}
]
}
foo
@@ -1,5 +1,5 @@
$ curl -H "Accept: application/json" -s \
'http://127.0.0.1:4434/self-service/recovery/flows?id=73fcb010-da5c-4eb9-b329-3ed677a6897b' | jq
'http://127.0.0.1:4433/self-service/recovery/flows?id=73fcb010-da5c-4eb9-b329-3ed677a6897b' | jq

{
"id": "73fcb010-da5c-4eb9-b329-3ed677a6897b",
Expand Down
Expand Up @@ -10,7 +10,7 @@ curl -s -v -X GET \
< HTTP/1.1 302 Found
< Cache-Control: 0
< Content-Type: text/html; charset=utf-8
< Location: http://127.0.0.1:4455/auth/settings?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3
< Location: http://127.0.0.1:4455/settings?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3
< Set-Cookie: csrf_token=y4Ocu6V83BapwJwbPw/pnlRHHw40DZbjq5iuDrxl0Ds=; Path=/; Domain=127.0.0.1; Max-Age=31536000; HttpOnly
<
<a href="http://127.0.0.1:4455/auth/settings?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3">Found</a>.
<a href="http://127.0.0.1:4455/settings?flow=df607aa1-d555-4b2a-b3e4-0f5a1d2fe6f3">Found</a>.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 70f2789

Please sign in to comment.