Skip to content

Commit c0cd2b0

Browse files
committed
Make token endpoint configurable and align with OAUTH
This patch makes the token endpoint configurable and anligns the request with OAUTH * https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1 Co-authored-by: Giuseppe Lo Presti <[email protected]> Signed-off-by: Micke Nordin <[email protected]>
1 parent b9c301d commit c0cd2b0

File tree

2 files changed

+130
-27
lines changed

2 files changed

+130
-27
lines changed

IETF-RFC.md

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ contain the following information about its OCM API:
653653
to the more secure (and possibly required) invite flow.
654654
_ `"receive-code"` - to indicate that this OCM Server can receive a
655655
`code` as part of a Share Creation Notification, and exchange it
656-
for a bearer token at the Sending Server's `/token` API endpoint.
656+
for a bearer token at the Sending Server's tokenEndPoint.
657657
_ `"invite-wayf"` - to indicate that this OCM Server exposes a WAYF
658658
Page to facilitate the Invite flow.
659659
* OPTIONAL: criteria (array of string) - The criteria for accepting a
@@ -695,6 +695,11 @@ contain the following information about its OCM API:
695695
`"/index.php/apps/sciencemesh/accept"` is specified here then a WAYF
696696
Page SHOULD redirect the end-user to
697697
`/index.php/apps/sciencemesh/accept?token=zi5kooKu3ivohr9a&providerDomain=example.com`.
698+
* OPTIONAL: tokenEndPoint (string) - URL of the token endpoint where
699+
the Sending Server can exchange a `code` for a bearer token.
700+
Implementations that offer the `"receive-code"` capability MUST
701+
provide this URL as well.
702+
Example: `"https://my-cloud-storage.org/ocm/token"`.
698703

699704
# Share Creation Notification
700705

@@ -767,7 +772,7 @@ To create a Share, the Sending Server SHOULD make a HTTP POST request
767772
that the share does not expire.
768773
* OPTIONAL code (string)
769774
A nonce to be exchanged for a (potentially short-lived)
770-
bearer token at the Sending Server's /token endpoint.
775+
bearer token at the Sending Server's tokenEndPoint [RFC6749]
771776
* REQUIRED protocol (object)
772777
JSON object with specific options for each protocol.
773778
The supported protocols are: - `webdav`, to access the data -
@@ -969,9 +974,10 @@ is as follows:
969974
`resourceTypes[0].protocols.webdav` value is the
970975
`<sender-ocm-path>` to be used in step 3.
971976
2. If `code` is not empty, the receiver SHOULD make a signed POST
972-
request to the `/token` path inside the Sending Server's OCM API, to
977+
request to the path in the Sending Server’s tokenEndPoint, to
973978
exchange the code for a short-lived bearer token, and then use that
974-
bearer token to access the Resource.
979+
bearer token to access the Resource (See the [Code Flow](
980+
#code-flow) section).
975981
3. If `protocol.name` = `webdav`, the receiver SHOULD inspect the
976982
`protocol.options` property. If it contains a `sharedSecret`, as in
977983
the [legacy example](
@@ -1002,6 +1008,83 @@ Additionally, if `protocol.<protocolname>.requirements` includes
10021008
Party has been authenticated with MFA, or prompt the consumer in order
10031009
to elevate their session, if applicable.
10041010

1011+
1012+
# Code Flow
1013+
1014+
This section defines the procedure for issuing short-lived bearer access
1015+
tokens for use by the Receiving Server when accessing a resource shared
1016+
through OCM. The mechanism is aligned with the OAuth 2.0
1017+
*authorization_code* grant type but is performed entirely as a
1018+
server to server interaction between the Sending and Receiving Servers.
1019+
No user interaction or redirect is involved. [RFC6749]
1020+
1021+
## Token Request
1022+
1023+
To obtain an access token, the Receiving Server MUST send an HTTP POST
1024+
request to the Sending Server’s tokenEndPoint as discovered in the
1025+
OCM provider metadata.
1026+
1027+
```
1028+
POST {tokenEndPoint} HTTP/1.1
1029+
Host: my-cloud-storage.org
1030+
Date: Wed, 05 Nov 2025 14:00:00 GMT
1031+
Content-Type: application/x-www-form-urlencoded
1032+
Digest: SHA-256=ok6mQ3WZzKc8nb7s/Jt2yY1uK7d2n8Zq7dhl3Q0s1xk=
1033+
Content-Length: 101
1034+
Signature-Input:
1035+
sig1=("@method" "@target-uri" "content-digest" "date"); \
1036+
created=1730815200; keyid="receiver.example.org#2025"; \
1037+
alg="rsa-sha256"
1038+
Signature: sig1=:
1039+
bM2sV2a4oM8pWc4Q8r9Zb8bQ7a2vH1kR9xT0yJ3uE4wO5lV6bZ1cP2rN3qD4tR5hC=:
1040+
1041+
grant_type=authorization_code&
1042+
client_id=receiver.example.org&
1043+
code=ABCD1234
1044+
```
1045+
1046+
The request MUST be signed using an HTTP Message Signature
1047+
[RFC9421]. The `client_id` identifies the Receiving Server and MUST be
1048+
set to it’s fully qualified domain name. The `code` parameter carries
1049+
the authorization code that was issued by the Sending Server in the
1050+
Share Creation Notification. It is allowed to send the additional
1051+
parameters defined in [RFC6749] for the authorization_code grant type,
1052+
but they MUST be ignored.
1053+
1054+
## Token Response
1055+
1056+
If the request is valid and the code is accepted, the Sending Server
1057+
MUST respond with HTTP 200 OK and a JSON object containing the issued
1058+
token:
1059+
1060+
```
1061+
{
1062+
"access_token": "8f3d3f26-f1e6-4b47-9e3e-9af6c0d4ad8b",
1063+
"token_type": "Bearer",
1064+
"expires_in": 300
1065+
}
1066+
```
1067+
The `access_token` is an opaque bearer credential with no internal
1068+
structure visible to the Receiving Server. The token authorizes the
1069+
Receiving Server to access the shared resource using the appropriate
1070+
transport protocol (e.g., WebDAV). The `expires_in` value indicates
1071+
the token lifetime in seconds. No `refresh_token` is issued, instead
1072+
the same request to the tokenEndPoint MUST be repeated before the
1073+
access_token has expired, to recieve a new `access_token` that can then
1074+
be used in the same manner.
1075+
1076+
## Error Responses
1077+
1078+
If the request is invalid, the Sending Server MUST return an HTTP 400
1079+
response with a JSON object containing an OAuth 2.0 error code
1080+
[RFC6749]:
1081+
```
1082+
{ "error": "invalid_request" }
1083+
```
1084+
1085+
Permitted error codes are `invalid_request`, `invalid_client`,
1086+
`invalid_grant`, `unauthorized_client` and `unsupported_grant_type`.
1087+
10051088
# Share Deletion
10061089

10071090
A `"SHARE_ACCEPTED"` notification followed by a `"SHARE_UNSHARED"`
@@ -1075,6 +1158,15 @@ The legacy format of an OCM Share Notification with shared secrets is
10751158
only provided for backwards compatibility with existing implementations.
10761159
Implementers SHOULD NOT use it and prefer short-lived tokens instead.
10771160

1161+
## Code Flow
1162+
1163+
All `{tokenEndPoint}` requests MUST be transmitted over HTTPS and
1164+
signed using HTTP Signatures. Bearer tokens MUST be treated as
1165+
confidential and never logged, persisted beyond their lifetime, or
1166+
transmitted over unsecured channels.
1167+
1168+
1169+
10781170
# References
10791171

10801172
## Normative References
@@ -1097,15 +1189,13 @@ Signatures](https://tools.ietf.org/html/rfc9421)", February 2024.
10971189
"[Uniform Resource Identifier (URI): Generic Syntax
10981190
](https://datatracker.ietf.org/doc/html/rfc3986)", January 2005
10991191

1192+
[RFC6749] Hardt, D. (ed), "[The OAuth 2.0 Authorization Framework](
1193+
https://datatracker.ietf.org/html/rfc6749)", October 2012.
1194+
11001195
[RFC8615] Nottingham, M. "[Well-Known Uniform Resource Identifiers
11011196
(URIs)](https://datatracker.ietf.org/doc/html/rfc8615)", May 2019
11021197

11031198

1104-
## Informative References
1105-
1106-
[RFC6749] Hardt, D. (ed), "[The OAuth 2.0 Authorization Framework](
1107-
https://datatracker.ietf.org/html/rfc6749)", October 2012.
1108-
11091199
# Appendix A: Multi-factor Authentication
11101200

11111201
If a Receiving Server exposes the capability `enforce-mfa`, it

spec.yaml

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -231,19 +231,20 @@ paths:
231231
application/json:
232232
schema:
233233
$ref: "#/components/schemas/Error"
234-
/token:
234+
/{tokenEndPoint}:
235235
post:
236236
summary: Token Exchange endpoint
237237
description: >
238238
This optional endpoint allows to obtain a (potentially short-lived) bearer token in exchange for a code.
239239
See [Resource Access](https://github.com/cs3org/OCM-API/blob/develop/IETF-RFC.md#resource-access)
240-
for more details.
240+
for more details. The actual endpoint URL is discovered via OCM provider metadata
241+
(tokenEndPoint).
241242
requestBody:
242243
content:
243-
application/json:
244+
application/x-www-form-urlencoded:
244245
schema:
245246
$ref: "#/components/schemas/TokenRequest"
246-
description: The JSON request body.
247+
description: Form-encoded request body.
247248
required: true
248249
responses:
249250
"200":
@@ -252,7 +253,7 @@ paths:
252253
application/json:
253254
schema:
254255
$ref: "#/components/schemas/TokenResponse"
255-
"403":
256+
"400":
256257
description: Token denied.
257258
content:
258259
application/json:
@@ -466,6 +467,12 @@ components:
466467
-----BEGIN PUBLIC KEY-----
467468
MII...QDD
468469
-----END PUBLIC KEY-----
470+
tokenEndPoint:
471+
type: string
472+
description: >
473+
Optional URL path of the Token Exchange endpoint to obtain bearer tokens in exchange for codes.
474+
If the `receive-code` capability is exposed, the tokenEndPoint MUST be advertised in the discovery response.
475+
example: /index.php/apps/sciencemesh/token
469476
inviteAcceptDialog:
470477
type: string
471478
description: >
@@ -554,7 +561,7 @@ components:
554561
type: string
555562
description: |
556563
A nonce to be exchanged for a (potentially short-lived) bearer token
557-
at the Sending Server's `/token` endpoint.
564+
at the Sending Server's {tokenEndPoint}.
558565
protocol:
559566
type: object
560567
description: |
@@ -637,9 +644,9 @@ components:
637644
MFA-authenticated. This requirement MAY be used if the
638645
recipient provider exposes the `enforce-mfa` capability.
639646
- `use-code` requires the recipient to exchange the given
640-
`code` via a signed HTTPS request to `/token` at the Sending
641-
Server, in order to get a short-lived token to be used for
642-
subsequent access. This requirement MAY be used if the
647+
`code` via a signed HTTPS request to {tokenEndPoint} at the
648+
Sending Server, in order to get a short-lived token to be used
649+
for subsequent access. This requirement MAY be used if the
643650
recipient provider exposes the `receive-code` capability.
644651
enum:
645652
- mfa-enforced
@@ -842,6 +849,10 @@ components:
842849
example: John Doe
843850
TokenRequest:
844851
type: object
852+
required:
853+
- grant_type
854+
- client_id
855+
- code
845856
properties:
846857
client_id:
847858
type: string
@@ -854,8 +865,14 @@ components:
854865
example: xyz
855866
grant_type:
856867
type: string
857-
description: Must be set to 'ocm_authorization_code'
858-
example: ocm_authorization_code
868+
description: Must be set to 'authorization_code'
869+
enum: ["authorization_code"]
870+
example: authorization_code
871+
redirect_uri:
872+
type: string
873+
description: >
874+
Optional parameter that MUST be ignored by the server.
875+
example: https://receiver.org/ocm/callback
859876
TokenResponse:
860877
type: object
861878
properties:
@@ -865,13 +882,9 @@ components:
865882
example: asdfgh
866883
token_type:
867884
type: string
868-
description: Must be set to 'bearer'
869-
example: bearer
885+
description: Must be set to 'Bearer'
886+
example: Bearer
870887
expires_in:
871888
type: number
872889
description: Number of seconds before this access_token will need to be refreshed.
873-
example: 3600
874-
refresh_token:
875-
type: string
876-
description: A refresh token
877-
example: qwertyuiop
890+
example: 300

0 commit comments

Comments
 (0)