Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -1508,10 +1508,11 @@ CREATE TABLE brig_test.prekeys (
CREATE TABLE brig_test.oauth_auth_code (
code ascii PRIMARY KEY,
client uuid,
code_challenge blob,
redirect_uri blob,
scope set<text>,
user uuid
) WITH bloom_filter_fp_chance = 0.1
) WITH bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
Expand Down Expand Up @@ -1648,7 +1649,7 @@ CREATE TABLE brig_test.password_reset (
retries int,
timeout timestamp,
user uuid
) WITH bloom_filter_fp_chance = 0.01
) WITH bloom_filter_fp_chance = 0.1
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
Expand Down
1 change: 1 addition & 0 deletions changelog.d/2-features/pr-3165
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Authorization Code Flow with PKCE support
36 changes: 21 additions & 15 deletions docs/src/developer/reference/oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The authorization server does the authentication of the user and establishes whe

### Supported OAuth flow

`wire-server` currently only supports the [authorization code flow](https://www.rfc-editor.org/rfc/rfc6749#section-4.1) which is optimized for confidential clients such as Outlook Calendar Extension.
`wire-server` currently only supports the [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](https://www.rfc-editor.org/rfc/rfc7636) which is optimized for public clients such as Outlook Calendar Extension.

```{image} oauth.svg
```
Expand Down Expand Up @@ -76,7 +76,7 @@ Client credentials will be generated and returned by wire-server:

These credentials have to be stored in a safe place and cannot be recovered if they are lost.

### Get authorization code
### Authorization request

When the user wants to use the 3rd party app for the first time, they need to authorize it to access Wire resources on their behalf.

Expand All @@ -86,6 +86,8 @@ If the user is already logged in the authentication will be skipped and they are

On the consent page, the user is asked to authorize the client's access request. They can either grant or deny the request and the corresponding scope, a list of permissions to give to the 3rd party app, (4. in diagram above).

The client needs to create a unique `code_verifier` as described in [RFC 7636 section 4.1](https://www.rfc-editor.org/rfc/rfc7636#section-4.1) and send a `code_challenge`, which is the unpadded base64url-encoded SHA256 hash of the code verifier as described in [RFC 7636 section 4.2](https://www.rfc-editor.org/rfc/rfc7636#section-4.2). The `code_challenge` must be included in the request. The `S256` code challenge method is mandatory. The `code_verifier` must not be included in the request.

Example request:

```http
Expand All @@ -94,18 +96,22 @@ GET /authorize?
response_type=code&
client_id=b9e65569-aa61-462d-915d-94c8d6ef17a7&
redirect_uri=https%3A%2F%2Fclient.example.com&
state=foobar HTTP/1.1
state=foobar&
code_challenge=qVrqDTN8ivyWEEw6wyfUc3bwhCA2RE4V2fbiC4mC7ofqAF4t&
code_challenge_method=S256 HTTP/1.1
```

Url encoded query parameters:

| Parameter | Description |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scope` | Required. The scope of the access request. |
| `response_type` | Required. Value MUST be set to `code`. |
| `client_id` | Required. The client identifier. |
| `redirect_url` | Required. MUST match the URL that was provided during client registration |
| `state` | Required. An opaque value used by the client to maintain state between the request and callback.</br>The authorization server includes this value when redirecting the user-agent back to the client.</br>The parameter is used for preventing cross-site request forgery. |
| Parameter | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scope` | Required. The scope of the access request. |
| `response_type` | Required. Value MUST be set to `code`. |
| `client_id` | Required. The client identifier. |
| `redirect_url` | Required. MUST match the URL that was provided during client registration |
| `state` | Required. An opaque value used by the client to maintain state between the request and callback.</br>The authorization server includes this value when redirecting the user-agent back to the client.</br>The parameter is used for preventing cross-site request forgery. |
| `code_challenge` | Required. Generated by the client from the `code_verifier` |
| `code_challenge_method` | Required. It MUST be set to `S256` |

Once the user consents, the browser will be redirected back to the 3rd party app, using the redirect URI provided during client registration, with an authorization code and the state value as query parameters (5. in diagram above). The authorization code can now be used by the 3rd party app to retrieve an access token and a refresh token and is good for one use.

Expand All @@ -127,7 +133,7 @@ The 3rd party app sends the authorization code together with the client credenti
```shell
curl -s -X POST server.example.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'code=1395a1a44b72e0b81ec8fe6c791d2d3f22bc1c4df96857a88c3e2914bb687b7b&client_id=b9e65569-aa61-462d-915d-94c8d6ef17a7&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fclient.example.com&client_secret=3f6fbd62835859b2bac411b2a2a2a54699ec56504ee32099748de3a762d41a2d'
-d 'code=1395a1a44b72e0b81ec8fe6c791d2d3f22bc1c4df96857a88c3e2914bb687b7b&client_id=b9e65569-aa61-462d-915d-94c8d6ef17a7&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fclient.example.com&code_verifier=2dae11ce5e162e2c01180ae4f8b55103b8297408b8aab12f99f63df3c2415234'
```

Parameters:
Expand All @@ -138,7 +144,7 @@ Parameters:
| `client_id` | Required. The client identifier. |
| `grant_type` | Required. Value MUST be set to `authorization_code`. |
| `redirect_uri` | Required. The value MUST be identical to the one provided in the authorization request |
| `client_secret` | Required. The client's secret. |
| `code_verifier` | Required. The code verifier as described above. |

Example response:

Expand All @@ -151,7 +157,7 @@ Example response:
}
```

The expiration time the response (`expires_in`) refers to the expiration time of the access token.
The expiration time in the response (`expires_in`) refers to the expiration time of the access token.

### Accessing a resource

Expand Down Expand Up @@ -205,8 +211,8 @@ curl -i -s -X POST localhost:8080/oauth/revoke \

Parameters:

| Parameter | Description |
| -------------- | ------------------------------------------------- |
| Parameter | Description |
| --------------- | ------------------------------------------------- |
| `client_id` | Required. The client identifier. |
| `refresh_token` | Required. The refresh token issued to the client. |
| `client_secret` | Required. The client's secret. |
Expand Down
18 changes: 18 additions & 0 deletions docs/src/developer/reference/oauth.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
sequenceDiagram
autonumber
actor U as User
participant C as Outlook Calendar Extension
participant A as Authorization Server (wire-server)
participant R as Resource Server (wire-server)

U->>C: Click login
C->>A: Authorization code request + code challenge /authorize
A->>U: Redirect to login/authorization prompt
U->>A: Authenticate and consent
A->>C: Authorization code
C->>A: Authorization code + code verifier
A->>A: Validate authorization code + code verifier
A->>C: Access token
C->>R: Request a resource with access token (e.g. POST /conversations)
R->>R: Validate access token with public key from auth server
R->>C: Response
2 changes: 1 addition & 1 deletion docs/src/developer/reference/oauth.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions libs/types-common/src/Data/Text/Ascii.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ module Data.Text.Ascii
AsciiBase64Url,
validateBase64Url,
encodeBase64Url,
encodeBase64UrlUnpadded,
decodeBase64Url,

-- * Base16 (Hex) Characters
Expand Down Expand Up @@ -310,6 +311,12 @@ validateBase64Url = validate
encodeBase64Url :: ByteString -> AsciiBase64Url
encodeBase64Url = unsafeFromByteString . B64Url.encode

-- | Encode a bytestring into a text containing only url-safe
-- base-64 characters. The resulting text is always a valid
-- encoding in unpadded form.
encodeBase64UrlUnpadded :: ByteString -> AsciiBase64Url
encodeBase64UrlUnpadded = unsafeFromByteString . B64Url.encodeUnpadded

-- | Decode a text containing only url-safe base-64 characters.
-- Decoding only succeeds if the text is a valid encoding and
-- a multiple of 4 bytes in length.
Expand Down
Loading