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
18 changes: 17 additions & 1 deletion openapi/cafe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,27 @@ components:
securitySchemes:
OAuth2:
type: oauth2
description: OAuth2 authorization for API access.
description: |
OAuth2 authorization for API access. The token endpoint accepts `grant_type=authorization_code`, `grant_type=client_credentials`, and `grant_type=refresh_token`.

### Differences from the OAuth2 specifications

A standard OAuth2 client library can drive these flows, with the following to account for.

Two behaviors do not conform to the specifications:

- **Errors use RFC 9457 problem+json, not RFC 6749 Section 5.2.** Failures return `application/problem+json` with `type`, `title`, `status`, and `instance`. There is no `error` or `error_description` field, so the standard codes (`invalid_grant`, `invalid_client`, `unsupported_grant_type`) never appear — branch on the HTTP status and `title` instead. A refresh token that is expired, already rotated, or unrecognized returns `400` with a `title` of `Refresh token has expired` or `Invalid refresh token`, where a conformant server would return `error: invalid_grant`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Medium

Deviating from the standard OAuth2 error format (error, error_description) in favor of RFC 9457 breaks compatibility with standard OAuth2 client libraries, potentially causing client-side failures or improper error handling in integrated applications.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will review it in other pr and align API codebase with documentation.

Comment thread
DmitryAnansky marked this conversation as resolved.
- **`refresh_token` is not a registrable grant type.** RFC 7591 Section 2 lists it, but `/oauth2/register` accepts only `authorization_code` and `client_credentials` in `grantTypes`. Refreshing requires no registration: holding a refresh token issued to the client is the authorization. A consequence is that refresh capability cannot be disabled per client — every `authorization_code` grant returns a refresh token, so a client intended for a shared or public device cannot be registered without one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Medium

Mandatory refresh_token for all authorization_code grants prevents clients on shared or public devices from opting out of long-lived session persistence, increasing risk of unauthorized access (RFC 6749 Section 4.1.4).


Two are choices the specifications leave to the server:

- **Refresh tokens rotate on every use.** A successful refresh retires the token presented and returns a replacement in `refresh_token`, as RFC 6749 Section 6 permits and the OAuth2 Security Best Current Practice recommends. Store the new value; the old one stops working. Refresh tokens expire 30 days after they are issued, and rotation restarts that window. The authorization code flow returns a refresh token with every access token; the client credentials flow returns none (RFC 6749 Section 4.4.3).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: High

Removing the /oauth2/revoke endpoint prevents clients from invalidating compromised or unused tokens (RFC 7009), extending the window of opportunity for attackers holding stolen access or refresh tokens until they naturally expire.

- **`scope` accepts commas.** The space-delimited form required by RFC 6749 is always accepted and recommended; comma-separated values are additionally tolerated.
Comment thread
DmitryAnansky marked this conversation as resolved.
flows:
authorizationCode:
authorizationUrl: https://api.cafe.redocly.com/oauth2/authorize
tokenUrl: https://api.cafe.redocly.com/oauth2/token
refreshUrl: https://api.cafe.redocly.com/oauth2/token
scopes:
menu:read: Read access to menu items and images
menu:write: Write access to menu items (create, delete)
Expand Down
12 changes: 11 additions & 1 deletion openapi/components/schemas/RegisterClientObject.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ properties:
items:
type: string
format: uri
default: []
description: List of redirect URIs (optional, defaults to empty array).
scopes:
type: array
Expand All @@ -19,6 +20,12 @@ properties:
- orders:read
- orders:write
- revenue:read
default:
- menu:read
- menu:write
- orders:read
- orders:write
- revenue:read
Comment thread
DmitryAnansky marked this conversation as resolved.
description: List of scopes.
grantTypes:
type: array
Expand All @@ -27,6 +34,9 @@ properties:
enum:
- authorization_code
- client_credentials
description: List of grant types.
default:
- authorization_code
- client_credentials
Comment thread
DmitryAnansky marked this conversation as resolved.
Comment thread
DmitryAnansky marked this conversation as resolved.
description: List of grant types. `refresh_token` is not registrable; any client holding a refresh token may present it at the token endpoint.
required:
- name
36 changes: 23 additions & 13 deletions openapi/paths/oauth2_register.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ post:
tags:
- Authorization
summary: Create OAuth2 client
description: >
Register a new OAuth2 client for dynamic client registration.
description: |
Register a new OAuth2 client for dynamic client registration.
This endpoint implements the Dynamic Client Registration Protocol (RFC 7591), using camelCase field names instead of the RFC's snake_case convention (e.g., `redirectUris` instead of `redirect_uris`, `grantTypes` instead of `grant_types`).
The `name` field is required. Other fields are optional. If not provided:

- `redirectUris` defaults to an empty array. Note: When using the
`authorization_code` grant type,
`redirectUris` must be provided (per RFC 7591 Section 2).
- `scopes` defaults to all available scopes (menu:read, menu:write,
orders:read, orders:write)
- `grantTypes` defaults to both supported grant types (authorization_code,
client_credentials)
- `redirectUris` defaults to an empty array. Note: When using the `authorization_code` grant type, `redirectUris` must be provided (per RFC 7591 Section 2).
- `scopes` defaults to all available scopes (menu:read, menu:write, orders:read, orders:write, revenue:read)
Comment thread
DmitryAnansky marked this conversation as resolved.
- `grantTypes` defaults to `authorization_code` and `client_credentials`
Comment thread
DmitryAnansky marked this conversation as resolved.
Comment thread
redocly[bot] marked this conversation as resolved.

These defaults interact: a request that supplies only `name` pairs `authorization_code` with an empty `redirectUris`, which is not a usable combination.
Supply `redirectUris` explicitly to register the `authorization_code` grant, or set `grantTypes` to `client_credentials` alone for a client that needs no redirect URI.
Comment thread
DmitryAnansky marked this conversation as resolved.

Refresh tokens require no registration and `refresh_token` is not a value you can register in `grantTypes`.
Comment thread
DmitryAnansky marked this conversation as resolved.
The token endpoint returns a refresh token alongside every access token it issues for the `authorization_code` grant, and accepts `grant_type=refresh_token` from any client presenting a refresh token issued to it.
The `client_credentials` grant returns no refresh token (RFC 6749 Section 4.4.3); those clients request a new access token with their own credentials instead.

Returns the registered client information per RFC 7591, including:

Expand All @@ -32,8 +35,6 @@ post:
RegisterClientObject:
dataValue:
Comment thread
DmitryAnansky marked this conversation as resolved.
name: auth
redirectUris:
- https://api.cafe.redocly.com/callback
scopes:
- menu:read
- menu:write
Expand All @@ -42,6 +43,17 @@ post:
- revenue:read
grantTypes:
- client_credentials
Comment thread
redocly[bot] marked this conversation as resolved.
RegisterClientForAuthorizationCode:
dataValue:
Comment thread
DmitryAnansky marked this conversation as resolved.
Comment thread
DmitryAnansky marked this conversation as resolved.
name: pos-terminal
redirectUris:
- https://api.cafe.redocly.com/callback
scopes:
- menu:read
- orders:read
- orders:write
grantTypes:
- authorization_code
responses:
'201':
description: OAuth2 client registered successfully.
Expand All @@ -51,7 +63,5 @@ post:
$ref: ../components/schemas/OAuth2Client.yaml
'400':
$ref: ../components/responses/BadRequest.yaml
'401':
$ref: ../components/responses/Unauthorized.yaml
'500':
$ref: ../components/responses/InternalServerError.yaml
Loading