Skip to content

Commit 77db232

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 7fb07d9 commit 77db232

File tree

2 files changed

+128
-27
lines changed

2 files changed

+128
-27
lines changed

IETF-RFC.md

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ contain the following information about its OCM API:
645645
to the more secure (and possibly required) invite flow.
646646
_ `"receive-code"` - to indicate that this OCM Server can receive a
647647
`code` as part of a Share Creation Notification, and exchange it
648-
for a bearer token at the Sending Server's `/token` API endpoint.
648+
for a bearer token at the Sending Server's tokenEndPoint.
649649
_ `"invite-wayf"` - to indicate that this OCM Server exposes a WAYF
650650
Page to facilitate the Invite flow.
651651
* OPTIONAL: criteria (array of string) - The criteria for accepting a
@@ -687,6 +687,11 @@ contain the following information about its OCM API:
687687
`"/index.php/apps/sciencemesh/accept"` is specified here then a WAYF
688688
Page SHOULD redirect the end-user to
689689
`/index.php/apps/sciencemesh/accept?token=zi5kooKu3ivohr9a&providerDomain=example.com`.
690+
* OPTIONAL: tokenEndPoint (string) - URL of the token endpoint where
691+
the Sending Server can exchange a `code` for a bearer token.
692+
Implementations that offer the `"receive-code"` capability MUST
693+
provide this URL as well.
694+
Example: `"https://my-cloud-storage.org/ocm/token"`.
690695

691696
# Share Creation Notification
692697

@@ -759,7 +764,7 @@ To create a Share, the Sending Server SHOULD make a HTTP POST request
759764
that the share does not expire.
760765
* OPTIONAL code (string)
761766
A nonce to be exchanged for a (potentially short-lived)
762-
bearer token at the Sending Server's /token endpoint.
767+
bearer token at the Sending Server's tokenEndPoint [RFC6749]
763768
* REQUIRED protocol (object)
764769
JSON object with specific options for each protocol.
765770
The supported protocols are: - `webdav`, to access the data -
@@ -961,9 +966,10 @@ is as follows:
961966
`resourceTypes[0].protocols.webdav` value is the
962967
`<sender-ocm-path>` to be used in step 3.
963968
2. If `code` is not empty, the receiver SHOULD make a signed POST
964-
request to the `/token` path inside the Sending Server's OCM API, to
969+
request to the path in the Sending Server’s tokenEndPoint, to
965970
exchange the code for a short-lived bearer token, and then use that
966-
bearer token to access the Resource.
971+
bearer token to access the Resource (See the [Code Flow](
972+
#code-flow) section).
967973
3. If `protocol.name` = `webdav`, the receiver SHOULD inspect the
968974
`protocol.options` property. If it contains a `sharedSecret`, as in
969975
the [legacy example](
@@ -994,6 +1000,81 @@ Additionally, if `protocol.<protocolname>.requirements` includes
9941000
Party has been authenticated with MFA, or prompt the consumer in order
9951001
to elevate their session, if applicable.
9961002

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

9991080
A `"SHARE_ACCEPTED"` notification followed by a `"SHARE_UNSHARED"`
@@ -1067,6 +1148,15 @@ The legacy format of an OCM Share Notification with shared secrets is
10671148
only provided for backwards compatibility with existing implementations.
10681149
Implementers SHOULD NOT use it and prefer short-lived tokens instead.
10691150

1151+
## Code Flow
1152+
1153+
All `{tokenEndPoint}` requests MUST be transmitted over HTTPS and
1154+
signed using HTTP Signatures. Bearer tokens MUST be treated as
1155+
confidential and never logged, persisted beyond their lifetime, or
1156+
transmitted over unsecured channels.
1157+
1158+
1159+
10701160
# References
10711161

10721162
## Normative References
@@ -1089,15 +1179,13 @@ Signatures](https://tools.ietf.org/html/rfc9421)", February 2024.
10891179
"[Uniform Resource Identifier (URI): Generic Syntax
10901180
](https://datatracker.ietf.org/doc/html/rfc3986)", January 2005
10911181

1182+
[RFC6749] Hardt, D. (ed), "[The OAuth 2.0 Authorization Framework](
1183+
https://datatracker.ietf.org/html/rfc6749)", October 2012.
1184+
10921185
[RFC8615] Nottingham, M. "[Well-Known Uniform Resource Identifiers
10931186
(URIs)](https://datatracker.ietf.org/doc/html/rfc8615)", May 2019
10941187

10951188

1096-
## Informative References
1097-
1098-
[RFC6749] Hardt, D. (ed), "[The OAuth 2.0 Authorization Framework](
1099-
https://datatracker.ietf.org/html/rfc6749)", October 2012.
1100-
11011189
# Appendix A: Multi-factor Authentication
11021190

11031191
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)