-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathIETF-OCM-IP.xml
More file actions
2172 lines (1880 loc) · 111 KB
/
Copy pathIETF-OCM-IP.xml
File metadata and controls
2172 lines (1880 loc) · 111 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.39 (Ruby 3.2.11) -->
<!DOCTYPE rfc [
<!ENTITY nbsp " ">
<!ENTITY zwsp "​">
<!ENTITY nbhy "‑">
<!ENTITY wj "⁠">
]>
<rfc ipr="trust200902" docName="draft-nordin-ocm-integration-protocol-00" category="std" consensus="true" submissionType="IETF">
<front>
<title>Open Cloud Mesh Integration Protocol</title>
<author initials="M." surname="Nordin" fullname="Micke Nordin">
<organization>SUNET</organization>
<address>
<email>kano@sunet.se</email>
<uri>https://code.smolnet.org/micke</uri>
</address>
</author>
<author initials="G." surname="Lo Presti" fullname="Giuseppe Lo Presti">
<organization>CERN</organization>
<address>
<email>giuseppe.lopresti@cern.ch</email>
<uri>https://cern.ch/lopresti</uri>
</address>
</author>
<author initials="M." surname="Baghbani" fullname="Mahdi Baghbani">
<organization>Ponder Source</organization>
<address>
<email>mahdi@pondersource.org</email>
<uri>https://pondersource.com</uri>
</address>
</author>
<date year="2026" month="June" day="13"/>
<area>Applications and Real-Time</area>
<keyword>Internet-Draft</keyword>
<abstract>
<?line 33?>
<t>The Open Cloud Mesh Integration Protocol (OCM-IP) defines how an Open
Cloud Mesh (OCM) Server can integrate supporting servers, such as
SSH/SFTP servers, web application platforms, or stand-alone WebDAV
servers, to perform protocol-specific work on its behalf.</t>
<t>OCM-IP makes it possible for existing OCM Servers to offload protocol
specific interactions to stand-alone servers, or even implement OCM as a
lightweight server that handles only the OCM parts of a deployment:
discovery, share creation, token issuance and signing. Anything
protocol-specific, such as serving files over WebDAV, providing SSH
access, or running an interactive web application, can be handed off to
one or more Protocol Servers running elsewhere, possibly operated with
different software and on different infrastructure.</t>
<t>OCM-IP defines three integration modes: a provisioned mode, in which the
OCM Server pushes Share information to the Protocol Server over a signed
back channel; a self-contained mode, in which the Share information is
embedded in the signed access token itself, so that the Protocol Server
needs no per-share state and no inbound API at all; and an introspected
mode, in which the Protocol Server validates presented credentials
through a token introspection endpoint, restoring compatibility with
Receiving Servers that do not support token exchange.</t>
<t>OCM-IP is a protocol between the Sending OCM Server and its Protocol
Servers only. The Receiving Server is not involved in, and does not
need to be aware of, this protocol: everything it observes is
indistinguishable from the Sending Server serving the access protocols
itself. For this reason, an OCM Sending Server MAY adopt a
different strategy to interoperate with Protocol Servers, including
e.g. establishing trust via shared keys, without compromising
compliance with the OCM protocol.</t>
</abstract>
</front>
<middle>
<?line 67?>
<section anchor="introduction"><name>Introduction</name>
<t>Open Cloud Mesh [OCM] is a server federation protocol used to notify a
Receiving Party that they have been granted access to some Resource.
OCM deliberately handles interactions only up to the point where the
Receiving Party is informed of their access; actual Resource access is
subsequently managed by other protocols, such as WebDAV [RFC4918], SSH,
or application-specific web protocols.</t>
<t>In existing deployments, the Sending Server typically implements both
the OCM endpoints and all of the access protocols it offers. This
couples the federation logic to the storage and application logic, and
makes it hard to:</t>
<t><list style="symbols">
<t>implement OCM as a small, auditable component in front of existing
infrastructure,</t>
<t>reuse a protocol implementation (for example a WebDAV server, an SFTP
server, or a computational notebook platform) across multiple OCM
deployments and vendors,</t>
<t>operate the access protocol on separate infrastructure from the OCM
Server, for example running a web application platform in a different
security domain than the file sync and share system.</t>
</list></t>
<t>This document defines the Open Cloud Mesh Integration Protocol (OCM-IP),
which decouples the two concerns. An OCM Server delegates the serving
of one or more access protocols to one or more Protocol Servers. The
OCM Server remains the single party that the rest of the federation
interacts with: it performs OCM API Discovery, receives and sends Share
Creation Notifications. The Protocol Server serves the actual Resource
access protocol, authorizing requests by independently verifying the
access tokens issued by the OCM Server.</t>
<t>Two properties of [OCM] make this delegation possible without sharing
secrets between the OCM Server and the Protocol Server:</t>
<t><list style="numbers" type="1">
<t>The OCM Server publishes its public keys at the Well-Known [RFC8615]
path <spanx style="verb">/.well-known/jwks.json</spanx> in JWK format [RFC7517], and signs its
server-to-server requests using HTTP Message Signatures [RFC9421].</t>
<t>The Code Flow lets the Receiving Server exchange the <spanx style="verb">sharedSecret</spanx>
for an access token whose format [OCM] leaves entirely at the issuer's
discretion.</t>
</list></t>
<t>OCM-IP uses that freedom: it requires the OCM Server to issue these
access tokens as JWTs conforming to the JWT Profile for OAuth 2.0 Access
Tokens [RFC9068], signed with the OCM Server's published key. Any
party, including a third-party service, can then verify such a token
without contacting the OCM Server on a per-request basis.</t>
<t>OCM-IP defines three integration modes that share a common authorization
core:</t>
<t><list style="symbols">
<t>Provisioned integration: a small back-channel API through which the
OCM Server provisions and revokes Share records on the Protocol Server,
ahead of any Resource access.</t>
<t>Self-contained integration: the OCM Server embeds the Share
information in the access token itself, as an additional JWT claim. The
Protocol Server keeps no per-share state and exposes no inbound API;
everything it needs arrives inside the signed token.</t>
<t>Introspected integration: the Protocol Server validates each presented
credential through a token introspection endpoint [RFC7662] at the OCM
Server. This is the compatibility mode: it is the only one that can
serve Receiving Servers that directly presents the legacy <spanx style="verb">sharedSecret</spanx>
instead of performing the token exchange.</t>
</list></t>
<t>In all modes, normative rules define how the Protocol Server authorizes
front-channel Resource access using the OCM credentials.</t>
<t>This document is intended to be useful to anyone who wants to write a
reusable server component for use with OCM, such that one implementation
of, say, a notebook platform integration can be used unchanged behind
OCM Servers from different vendors.</t>
</section>
<section anchor="terms"><name>Terms</name>
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in BCP 14
[RFC2119] [RFC8174] when, and only when, they appear in all capitals, as
shown here.</t>
<t>This document reuses the following terms as defined in [OCM]:
<em>Resource</em>, <em>Share</em>, <em>Share Creation Notification</em>, <em>Sending Server</em>,
<em>Receiving Server</em>, <em>Sending Party</em>, <em>Receiving Party</em>, <em>OCM Address</em>,
<em>OCM Server</em>, and <em>Code Flow</em>.</t>
<t>In addition, we define:</t>
<t><list style="symbols">
<t><strong>Protocol Server</strong> - A server that serves one or more access
protocols (e.g., WebDAV, SSH, a web application) for Resources shared
through an OCM Server, on that OCM Server's behalf.</t>
<t><strong>Integration API</strong> - The back-channel HTTP API exposed by a Protocol
Server, through which a paired OCM Server provisions and revokes Share
records.</t>
<t><strong>Pairing</strong> - The out-of-band configuration step by which an OCM
Server and a Protocol Server are introduced to each other, establishing
mutual trust (see Pairing section).</t>
<t><strong>Share Provisioning Request</strong> - A signed back-channel request from
the OCM Server to the Protocol Server, transferring the information the
Protocol Server needs in order to serve a Share.</t>
<t><strong>Share Revocation Request</strong> - A signed back-channel request from the
OCM Server to the Protocol Server, instructing it to stop serving a
Share and release any associated resources.</t>
<t><strong>Share Record</strong> - The Protocol Server's stored representation of a
provisioned Share, keyed by the pair (sender domain, providerId).</t>
<t><strong>Provisioned Integration</strong> - The integration mode in which the OCM
Server transfers Share information to the Protocol Server over the back
channel, before any Resource access takes place.</t>
<t><strong>Self-Contained Integration</strong> - The integration mode in which the
Share information travels inside the access token, in the <spanx style="verb">ocm_ip</spanx>
claim, and no back channel is used.</t>
<t><strong>Introspected Integration</strong> - The integration mode in which the
Protocol Server validates a presented credential by querying a token
introspection endpoint [RFC7662] hosted by the OCM Server (or its
delegated Token Server). Defined for backwards compatibility with
Receiving Servers that do not support the Code Flow.</t>
<t><strong>ocm_ip Claim</strong> - A JWT claim, defined by this document, whose value
is an object carrying the Share information a Protocol Server needs in
order to serve a Share in Self-Contained Integration.</t>
<t><strong>Front Channel</strong> - The path through which Resource access requests
reach the Protocol Server, originating from the Receiving Server or from
the Receiving Party's user agent, carrying a credential issued by the
OCM Server: an access token or, in Introspected Integration, possibly
the legacy <spanx style="verb">sharedSecret</spanx>.</t>
<t><strong>Back Channel</strong> - The direct, signed, server-to-server path between
the OCM Server and the Protocol Server, carrying the Integration API
requests.</t>
</list></t>
</section>
<section anchor="architecture"><name>Architecture</name>
<section anchor="integration-modes"><name>Integration Modes</name>
<t>An OCM Server that delegates protocol work takes on the Sending Server
role of [OCM] towards the federation. Towards its Protocol Servers it
uses one of three integration modes, chosen per pairing and per Share:</t>
<t><list style="symbols">
<t>In <strong>Provisioned Integration</strong>, the OCM Server acts as a client of the
Protocol Server's Integration API: it pushes a Share Record over the
signed back channel before the Share is created, and revokes it when the
Share ends. This mode supports the full Share lifecycle, including
prompt revocation and the release of per-share resources, and is the
only mode that supports SSH.</t>
<t>In <strong>Self-Contained Integration</strong>, there is no back channel at all:
the OCM Server embeds the Share information in the access token, in the
<spanx style="verb">ocm_ip</spanx> claim. The Protocol Server is stateless with respect to
Shares, which makes this mode attractive for simple gateways (for
example a token-verifying WebDAV front end to an existing storage
system), at the cost of revocation latency bounded only by token
lifetime (see Lifecycle).</t>
<t>In <strong>Introspected Integration</strong>, the Protocol Server validates each
presented credential by querying a token introspection endpoint
[RFC7662] at the OCM Server (or its delegated Token Server). This is a
compatibility mode: it is the only mode that can serve Receiving Servers
that do not support the <spanx style="verb">exchange-token</spanx> capability and therefore
present the legacy <spanx style="verb">sharedSecret</spanx> directly on the front channel. It
reintroduces a per-request dependency on the OCM Server, which the other
two modes avoid.</t>
</list></t>
<t>A Protocol Server MAY support any combination of the modes. Protocols
that allocate per-share resources or sessions (for example a notebook
platform that starts a computational session per Share) SHOULD use
Provisioned Integration, since Self-Contained Integration provides no
signal to release such resources. Introspected Integration SHOULD be
used only where it is needed, namely for Shares towards Receiving
Servers that cannot perform the token exchange; where the Code Flow is
available, the other two modes avoid the per-request coupling.</t>
</section>
<section anchor="provisioned-integration-flow"><name>Provisioned Integration Flow</name>
<figure><artwork><![CDATA[
Sending OCM Server Protocol Receiving Receiving
Party (Sending Server) Server Server Party
| | | | |
| 1. Sending | | | |
| Gesture | | | |
|----------->| | | |
| | 2. Share | | |
| | Provisioning | | |
| | Request | | |
| |------------->| | |
| | 3. 201 | | |
| |<-------------| | |
| | 4. Share Creation | |
| | Notification | |
| |--------------------------->| |
| | | | 5. notify |
| | | |----------->|
| | 6. Token Request | |
| | (Code Flow) | |
| |<---------------------------| |
| | 7. access_token (JWT) | |
| |--------------------------->| |
| | | 8. Resource access |
| | | with access_token |
| | |<------------+------------|
| | | 9. verify token against |
| | | OCM Server's JWKS, |
| | | look up Share Record, |
| | | serve the protocol |
]]></artwork></figure>
<t>The numbered steps are:</t>
<t><list style="numbers" type="1">
<t>The Sending Party makes a Sending Gesture to the OCM Server, as
described in [OCM].</t>
<t>The OCM Server sends a Share Provisioning Request over the back
channel to the Protocol Server responsible for (one or more of) the
protocols offered in the Share.</t>
<t>The Protocol Server verifies the request signature, stores the Share
Record and acknowledges.</t>
<t>The OCM Server sends the Share Creation Notification to the Receiving
Server, exactly as specified in [OCM]. The protocol endpoints
advertised in the notification point (directly or via a reverse proxy)
at the Protocol Server.</t>
<t>The Receiving Server notifies the Receiving Party as usual.</t>
<t>The Receiving Server exchanges the <spanx style="verb">sharedSecret</spanx> for an access token
at the OCM Server's <spanx style="verb">tokenEndPoint</spanx>, using the Code Flow of [OCM].</t>
<t>The OCM Server issues a signed JWT access token whose <spanx style="verb">client_id</spanx>
claim equals the <spanx style="verb">providerId</spanx> of the Share provisioned in step 2.</t>
<t>The Receiving Server (or the Receiving Party's user agent, depending
on the access protocol) presents the access token to the Protocol
Server.</t>
<t>The Protocol Server verifies the token against the OCM Server's
published keys, looks up the Share Record by (issuer domain,
<spanx style="verb">client_id</spanx>), cross-checks the identities bound into the token, and
serves the protocol-specific Resource access.</t>
</list></t>
</section>
<section anchor="self-contained-integration-flow"><name>Self-Contained Integration Flow</name>
<figure><artwork><![CDATA[
Sending OCM Server Protocol Receiving Receiving
Party (Sending Server) Server Server Party
| | | | |
| 1. Sending | | | |
| Gesture | | | |
|----------->| | | |
| | 2. Share Creation | |
| | Notification | |
| |--------------------------->| |
| | | | 3. notify |
| | | |----------->|
| | 4. Token Request | |
| | (Code Flow) | |
| |<---------------------------| |
| | 5. access_token (JWT | |
| | with ocm_ip claim) | |
| |--------------------------->| |
| | | 6. Resource access |
| | | with access_token |
| | |<------------+------------|
| | | 7. verify token against |
| | | OCM Server's JWKS, |
| | | check issuer pairing, |
| | | serve per the ocm_ip |
| | | claim |
]]></artwork></figure>
<t>The flow is the OCM flow unchanged, except that the token issued in step
5 carries the <spanx style="verb">ocm_ip</spanx> claim, and that the protocol endpoints advertised
in step 2 point at the Protocol Server. The Protocol Server is not
contacted before Resource access, holds no Share Records, and learns of
each Share only when the first request for it arrives.</t>
</section>
<section anchor="introspected-integration-flow"><name>Introspected Integration Flow</name>
<figure><artwork><![CDATA[
Sending OCM Server Protocol Receiving Receiving
Party (Sending Server) Server Server Party
| | | | |
| 1. Sending | | | |
| Gesture | | | |
|----------->| | | |
| | 2. Share Creation | |
| | Notification | |
| | (legacy sharedSecret) | |
| |--------------------------->| |
| | | | 3. notify |
| | | |----------->|
| | | 4. Resource access |
| | | with sharedSecret |
| | |<------------+------------|
| | 5. Token Introspection | |
| | Request (signed) | |
| |<-------------| | |
| | 6. active + Share | |
| | information | |
| |------------->| | |
| | | 7. serve per the |
| | | introspection |
| | | response |
]]></artwork></figure>
<t>The Share Creation Notification in step 2 is a legacy [OCM] share: it
carries the <spanx style="verb">sharedSecret</spanx> and does not include <spanx style="verb">must-exchange-token</spanx>,
because the Receiving Server cannot honor it. The Protocol Server
validates the presented credential by introspecting it at the OCM Server
(steps 5 and 6) and authorizes the request from the introspection
response.</t>
<t>Introspected Integration composes with Provisioned Integration for the
same Share: in that case the introspection response identifies the
provisioned Share Record via <spanx style="verb">client_id</spanx>, and introspection replaces
only the credential validation, not the lifecycle handling.</t>
</section>
<section anchor="relationship-to-open-cloud-mesh"><name>Relationship to Open Cloud Mesh</name>
<t>OCM-IP is layered strictly behind the Sending Server role of [OCM]:</t>
<t><list style="symbols">
<t>The OCM Server remains the Discoverable Server. Protocol Servers MUST
NOT be required to expose <spanx style="verb">/.well-known/ocm</spanx>.</t>
<t>The OCM Server remains the recipient of Invite Acceptance Requests,
Share Acceptance Notifications and all other OCM endpoints.</t>
<t>The OCM Server remains the OAuth Authorization Server towards the
federation: access tokens are issued under its identity and verified
against the keys it publishes. The hosting of the <spanx style="verb">tokenEndPoint</spanx>
itself MAY however be delegated as well; see the note below.</t>
<t>The Protocol Server takes on (part of) the OAuth Resource Server
function: it is the party that ultimately accepts access tokens in
exchange for Resource access.</t>
</list></t>
<t>Shares whose protocols are served by a Protocol Server MUST use the Code
Flow of [OCM] unless the Share uses Introspected Integration: the OCM
Server MUST include <spanx style="verb">must-exchange-token</spanx> in the requirements of every
protocol entry that a Protocol Server serves in Provisioned or
Self-Contained Integration. Legacy shared-secret access cannot be
verified by a Protocol Server on its own, because the long-lived secret
is deliberately never replicated to it; Introspected Integration exists
precisely to close this gap for Receiving Servers that cannot perform
the token exchange, at the cost of a per-request callback (see Token
Introspection and Security Considerations).</t>
<section anchor="note-delegating-the-token-endpoint"><name>Note: Delegating the Token Endpoint</name>
<t>This note is non-normative.</t>
<t>The <spanx style="verb">tokenEndPoint</spanx> is advertised as an absolute URL in the OCM Server's
discovery document, and nothing in [OCM] requires it to be served from
the OCM Server's own host. Token issuance can therefore, in principle,
be delegated to a separate Token Server, in the same spirit as the rest
of this document:</t>
<t><list style="symbols">
<t>The Token Server holds its own signing keypair, and the OCM Server
publishes the public key in its own <spanx style="verb">/.well-known/jwks.json</spanx> under a
<spanx style="verb">kid</spanx> in its own domain. The <spanx style="verb">iss</spanx> and <spanx style="verb">kid</spanx> rules of this document
(see Token Issuance by the OCM Server) are then satisfied without any
private key leaving the Token Server, and token
verification by Receiving Servers and Protocol Servers is unchanged.</t>
<t>The Token Server learns about Shares through a special case of the
back channel: a share preparation request, by which the OCM Server sends
the information needed for issuance (the parties, the <spanx style="verb">providerId</spanx> or
the <spanx style="verb">ocm_ip</spanx> contents, the expiration) and receives in response a
<spanx style="verb">sharedSecret</spanx> minted by the Token Server. The OCM Server forwards that
secret to the Receiving Server in the Share Creation Notification,
without needing to retain it. The code presented in the Code Flow is
thereby validated by the very server that minted it, and the secret is
never stored outside the Token Server.</t>
</list></t>
<t>In such a deployment the OCM Server is reduced to pure federation logic:
discovery, Share bookkeeping, notifications and invites, with both token
issuance and Resource access served elsewhere. The share preparation
request is identical to a request sent over the normal back channel, the
only difference being that the response from the Token Server includes
the <spanx style="verb">sharedSecret</spanx>.</t>
</section>
</section>
<section anchor="the-transparency-requirement"><name>The Transparency Requirement</name>
<t>OCM-IP is purely a protocol between the Sending Server and the Protocol
Server. The Receiving Server MUST NOT be required to implement, or even
be aware of, OCM-IP.</t>
<t>Concretely, everything observable by the Receiving Server and the
Receiving Party MUST be indistinguishable from a deployment in which the
Sending Server serves the access protocols itself:</t>
<t><list style="symbols">
<t>The protocol endpoints advertised in OCM API Discovery and in Share
Creation Notifications are ordinary URIs (or <spanx style="verb">host:port</spanx> addresses for
SSH); whether they are served by the OCM Server, by a reverse proxy in
front of a Protocol Server, or by a Protocol Server on a different
hostname is invisible at the OCM layer.</t>
<t>Access tokens are obtained from the OCM Server's <spanx style="verb">tokenEndPoint</spanx> and
presented to the advertised protocol endpoint, exactly as specified in
[OCM].</t>
<t>Errors returned by the Protocol Server on the front channel use the
semantics of the access protocol concerned.</t>
</list></t>
<t>A consequence of this requirement is that no OCM capability or criterium
is defined for OCM-IP: there is nothing for a remote peer to discover.</t>
</section>
<section anchor="topologies"><name>Topologies</name>
<t>The mapping between OCM Servers and Protocol Servers is many-to-many:</t>
<t><list style="symbols">
<t>An OCM Server MAY pair with multiple Protocol Servers, for example one
serving WebDAV and another serving a web application platform, and MAY
provision the same Share to more than one of them when the Share offers
multiple protocols.</t>
<t>A Protocol Server MAY be paired with multiple OCM Servers. Share
Records are keyed by the pair (sender domain, providerId), so records
provisioned by different OCM Servers cannot collide and access tokens
issued by one OCM Server cannot address records provisioned by another.
In Self-Contained Integration the same isolation holds trivially: a
token is honored only if its issuer is paired, and grants only what its
own claims describe.</t>
</list></t>
</section>
</section>
<section anchor="pairing"><name>Pairing</name>
<t>Before a Protocol Server serves any Share, the OCM Server and the
Protocol Server MUST be paired. Pairing is performed out of band,
typically by the operators of the two systems, and consists of at least:</t>
<t><list style="symbols">
<t>On the OCM Server: which protocols and resource types the Protocol
Server is responsible for, which integration mode(s) to use, and, for
Provisioned Integration, the base URL of the Integration API of the
Protocol Server (referred to as <spanx style="verb">{integrationAPI}</spanx> below). For
Introspected Integration, additionally the domain of the Protocol
Server, used to verify its introspection requests.</t>
<t>On the Protocol Server: the domain(s) of the paired OCM Server(s) and
the integration mode(s) permitted for each. The Protocol Server MUST
maintain an allowlist of paired OCM Server domains, MUST reject
Integration API requests whose sender is not on that allowlist, and MUST
NOT honor the <spanx style="verb">ocm_ip</spanx> claim of tokens whose issuer is not paired for
Self-Contained Integration. For Introspected Integration, additionally
the URL of the introspection endpoint (referred to as
<spanx style="verb">{introspectionEndPoint}</spanx> below).</t>
</list></t>
<t>No shared secret is exchanged during pairing. All trust on the back
channel derives from HTTP Message Signatures [RFC9421] made with the OCM
Server's signatory key, verified against the keys the OCM Server
publishes at <spanx style="verb">https://<domain>/.well-known/jwks.json</spanx> [RFC7517], as
specified in [OCM]. All trust on the front channel derives from the JWT
signatures on the access tokens, verified against the same published
keys. Trust in introspection requests derives, symmetrically, from HTTP
Message Signatures made with the Protocol Server's key, published at the
Protocol Server's own <spanx style="verb">/.well-known/jwks.json</spanx>.</t>
<t>The Protocol Server consequently does not need a signing keypair of its
own to implement this protocol, unless it uses Introspected Integration,
which requires it to sign its introspection requests (see Token
Introspection).</t>
</section>
<section anchor="integration-api"><name>Integration API</name>
<t>The Integration API is the back channel of Provisioned Integration. A
Protocol Server that supports only Self-Contained Integration does not
expose it, and an OCM Server never calls it for self-contained Shares.</t>
<section anchor="general-requirements"><name>General Requirements</name>
<t>All Integration API requests:</t>
<t><list style="symbols">
<t>MUST be made over TLS (implementations MAY fall back to plain HTTP in
testing setups only),</t>
<t>MUST use the HTTP POST method with <spanx style="verb">application/json</spanx> as the
<spanx style="verb">Content-Type</spanx> request header,</t>
<t>MUST be signed with an HTTP Message Signature [RFC9421] carrying the
label <spanx style="verb">ocm</spanx>, following the same rules as server-to-server requests in
[OCM]: the signature MUST cover at least <spanx style="verb">@method</spanx>, <spanx style="verb">@target-uri</spanx>,
<spanx style="verb">content-digest</spanx>, <spanx style="verb">content-length</spanx> and <spanx style="verb">date</spanx>, MUST include the
<spanx style="verb">created</spanx> parameter, and MUST be made with an asymmetric algorithm using
a key advertised in the OCM Server's <spanx style="verb">/.well-known/jwks.json</spanx>.</t>
</list></t>
<t>On receipt of an Integration API request, the Protocol Server:</t>
<t><list style="numbers" type="1">
<t>MUST parse the <spanx style="verb">sender</spanx> field from the request body and derive the
sender domain from the part after the last <spanx style="verb">@</spanx> sign.</t>
<t>MUST verify that the sender domain is on its allowlist of paired OCM
Servers, and reject the request with HTTP status 401 otherwise.</t>
<t>MUST verify the <spanx style="verb">ocm</spanx>-labeled signature against the JWKS of the
sender domain, following the verification rules of [OCM] (single <spanx style="verb">ocm</spanx>
label, required covered components, content-digest match [RFC9530],
<spanx style="verb">created</spanx>
within a freshness window, <spanx style="verb">keyid</spanx> domain equal to the sender domain),
and reject the request with HTTP status 401 on any failure.</t>
</list></t>
<t>Note that, unlike the Share Creation Notification of [OCM], where the
verification key is discovered from the <spanx style="verb">sender</spanx> field of an arbitrary
remote server, the allowlist check in step 2 happens before any key
fetching: a Protocol Server never fetches keys from, or processes
payloads of, servers it is not paired with.</t>
<t>If the Protocol Server is deployed behind a TLS-terminating reverse
proxy, it MUST reconstruct the <spanx style="verb">@target-uri</spanx> that the OCM Server signed
(i.e., the public URL) when verifying signatures, for example from
forwarding headers set by the proxy.</t>
</section>
<section anchor="share-provisioning-request"><name>Share Provisioning Request</name>
<t>To provision a Share, the OCM Server MUST send a Share Provisioning
Request:</t>
<t><list style="symbols">
<t>to <spanx style="verb">{integrationAPI}/shares</spanx>,</t>
<t>before sending the corresponding Share Creation Notification to the
Receiving Server (see Lifecycle below),</t>
<t>with a request body containing a JSON document as described below.</t>
</list></t>
<section anchor="fields"><name>Fields</name>
<t>The request body is the Share Creation Notification object of [OCM] that
the OCM Server intends to send to the Receiving Server, with one
transformation applied: every <spanx style="verb">sharedSecret</spanx> field, in every protocol
entry, MUST be removed. The Protocol Server never receives, stores, or
needs any OCM secret.</t>
<t>The fields used by the Protocol Server are thus:</t>
<t><list style="symbols">
<t>REQUIRED <spanx style="verb">sender</spanx> (string) - OCM Address of the user that creates the
Share. The domain part identifies the paired OCM Server and selects the
verification keys, as described above.</t>
<t>REQUIRED <spanx style="verb">owner</spanx> (string) - OCM Address of the user that owns the
Resource. Used for identity binding on the front channel.</t>
<t>REQUIRED <spanx style="verb">shareWith</spanx> (string) - OCM Address of the Receiving Party.
Used for identity binding on the front channel.</t>
<t>REQUIRED <spanx style="verb">providerId</spanx> (string) - as in [OCM]; opaque identifier of the
Share at the OCM Server, unique per Share. It keys the Share Record and
links the back channel to the front channel (see below).</t>
<t>REQUIRED <spanx style="verb">shareType</spanx> (string) - as in [OCM].</t>
<t>REQUIRED <spanx style="verb">resourceType</spanx> (string) - as in [OCM].</t>
<t>REQUIRED <spanx style="verb">protocol</spanx> (object) - as in [OCM], transformed as described
above. The protocol entries carry the protocol-specific information the
Protocol Server needs to serve the Share (for example the <spanx style="verb">webdav</spanx>
entry's <spanx style="verb">uri</spanx> and <spanx style="verb">permissions</spanx>, or the <spanx style="verb">webapp</spanx> entry's <spanx style="verb">viewMode</spanx>).</t>
<t>OPTIONAL <spanx style="verb">name</spanx>, <spanx style="verb">description</spanx>, <spanx style="verb">ownerDisplayName</spanx>,
<spanx style="verb">senderDisplayName</spanx>, <spanx style="verb">expiration</spanx> - as in [OCM]; informational, except
<spanx style="verb">expiration</spanx>, which the Protocol Server SHOULD honor (see Lifecycle).</t>
</list></t>
<t>Additional fields from the Share Creation Notification MAY be present
and MUST be ignored if not understood.</t>
</section>
<section anchor="the-providerid"><name>The providerId</name>
<t>The <spanx style="verb">providerId</spanx> is the link between the back channel and the front
channel, and the following rules apply:</t>
<t><list style="symbols">
<t>[OCM] guarantees that the <spanx style="verb">providerId</spanx> is unique per Share, so the
pair (sender domain, providerId) identifies exactly one Share Record.</t>
<t>The OCM Server MUST set the <spanx style="verb">client_id</spanx> claim of every access token it
issues for this Share (via its <spanx style="verb">tokenEndPoint</spanx>) to exactly the
<spanx style="verb">providerId</spanx>. This constrains a value that the token profile of this
document (see Token Issuance by the OCM Server) otherwise leaves at the
OCM Server's discretion.</t>
<t>The <spanx style="verb">providerId</spanx> is an identifier, not a credential: the Receiving
Server learns it from the Share Creation Notification anyway.
Possession of a <spanx style="verb">providerId</spanx> MUST NOT grant any access by itself; all
front channel authorization derives from the verified access token.
Consequently, the <spanx style="verb">providerId</spanx> does not need to be unguessable, and it
MAY appear in URLs and logs.</t>
</list></t>
</section>
<section anchor="response"><name>Response</name>
<t>On success the Protocol Server MUST respond with HTTP status 201 and a
JSON object with the following fields:</t>
<t><list style="symbols">
<t>OPTIONAL <spanx style="verb">status</spanx> (string) - e.g. <spanx style="verb">"stored"</spanx>.</t>
<t>OPTIONAL <spanx style="verb">protocol</spanx> (object) - protocol details allocated by the
Protocol Server for this Share, in the same format as the <spanx style="verb">protocol</spanx>
object of [OCM].</t>
</list></t>
<t>When the response contains a <spanx style="verb">protocol</spanx> object, the OCM Server SHOULD
use its field values (for example, a per-share <spanx style="verb">uri</spanx> allocated by the
Protocol Server) when constructing the corresponding protocol entries of
the outbound Share Creation Notification, in place of statically
configured values from the pairing. This allows a Protocol Server to
allocate endpoints dynamically, per Share.</t>
<t>Two restrictions apply to the response <spanx style="verb">protocol</spanx> object:</t>
<t><list style="symbols">
<t>It MUST NOT contain <spanx style="verb">sharedSecret</spanx> fields, and an OCM Server MUST
ignore any <spanx style="verb">sharedSecret</spanx> found in a Share Provisioning Response.
(Delegated token issuance is the exception: the share preparation
request is this same request sent to a Token Server, whose response
legitimately carries the <spanx style="verb">sharedSecret</spanx> it minted; see the note on
delegating the token endpoint.)</t>
<t>The OCM Server MUST NOT take permissions from the response: the
Share's permissions are decided by the Sending Party and the OCM Server,
never by the Protocol Server.</t>
</list></t>
<t>Fields in the response <spanx style="verb">protocol</spanx> object that the OCM Server does not
understand MUST be ignored.</t>
<t>A Share Provisioning Request for a (sender domain, providerId) pair that
already has a Share Record MUST replace the existing record and respond
with HTTP status 201. This makes provisioning idempotent and gives the
OCM Server a way to update a Share (for example after a permissions
change) by re-provisioning it.</t>
<t>Error responses:</t>
<t><list style="symbols">
<t>400 - the request body is not valid JSON, or a required field is
missing or malformed.</t>
<t>401 - the signature is missing, malformed, stale or invalid, or the
sender domain is not on the allowlist of paired OCM Servers.</t>
<t>503 - the Protocol Server is temporarily unable to provision the
Share.</t>
</list></t>
</section>
</section>
<section anchor="share-revocation-request"><name>Share Revocation Request</name>
<t>When a Share is deleted, expires, is declined by the Receiving Party, or
access is otherwise withdrawn, the OCM Server SHOULD send a Share
Revocation Request:</t>
<t><list style="symbols">
<t>to <spanx style="verb">{integrationAPI}/revoke</spanx>,</t>
<t>with a request body containing a JSON document with the following
fields:</t>
<t>REQUIRED <spanx style="verb">sender</spanx> (string) - an OCM Address whose domain part
identifies the paired OCM Server, subject to the same allowlist and
signature checks as all Integration API requests.</t>
<t>REQUIRED <spanx style="verb">providerId</spanx> (string) - the <spanx style="verb">providerId</spanx> of the Share to
revoke.</t>
</list></t>
<t>On receipt of a valid Share Revocation Request, the Protocol Server MUST
stop serving the identified Share, MUST delete the Share Record, and
SHOULD release any resources associated with it (for example, stopping a
computational session that was started for the Share, or invalidating
local sessions derived from its access tokens).</t>
<section anchor="response-1"><name>Response</name>
<t>Revocation MUST be idempotent: if no Share Record exists for the given
(sender domain, providerId), the Protocol Server MUST respond with HTTP
status 200, so that the OCM Server can treat revocation as
fire-and-forget. This document defines one OPTIONAL response field:</t>
<t><list style="symbols">
<t>OPTIONAL <spanx style="verb">status</spanx> (string) - e.g. <spanx style="verb">"revoked"</spanx> when a record was found
and revoked, <spanx style="verb">"gone"</spanx> when there was nothing to revoke.</t>
</list></t>
<t>Error responses are as for Share Provisioning.</t>
</section>
</section>
<section anchor="liveness"><name>Liveness</name>
<t>A Protocol Server SHOULD respond to a GET request to <spanx style="verb">{integrationAPI}</spanx>
(or <spanx style="verb">{integrationAPI}/</spanx>) with HTTP status 200 and a JSON object, so that
operators and OCM Servers can verify reachability of the Integration
API. The contents of the object are not specified.</t>
</section>
</section>
<section anchor="token-introspection"><name>Token Introspection</name>
<t>Token introspection is the credential validation path of Introspected
Integration. The introspection endpoint is hosted by the OCM Server or,
when token issuance is delegated, by its Token Server; its URL,
<spanx style="verb">{introspectionEndPoint}</spanx>, is exchanged during pairing. It is not
advertised in the OCM discovery document: like the Integration API, it
is invisible to the federation.</t>
<t>Note that a legacy credential is opaque and carries no issuer
information, so the Protocol Server has no way to determine which paired
OCM Server to introspect against; Introspected Integration therefore
cannot work in multi-tenant deployments, where one Protocol Server
serves more than one OCM Server through the same protocol endpoint.</t>
<section anchor="request"><name>Request</name>
<t>To validate a presented credential, the Protocol Server sends an HTTP
POST request to <spanx style="verb">{introspectionEndPoint}</spanx> as specified by [RFC7662]: the
request body is <spanx style="verb">application/x-www-form-urlencoded</spanx> with a <spanx style="verb">token</spanx>
parameter carrying the credential exactly as presented on the front
channel. The credential MAY be a legacy <spanx style="verb">sharedSecret</spanx> or a JWT access
token; the endpoint MUST accept any credential that is valid for a Share
at this OCM Server.</t>
<t>The request MUST be made over TLS and MUST be signed with an HTTP
Message Signature [RFC9421] carrying the label <spanx style="verb">ocm</spanx>, with the same
covered components and <spanx style="verb">created</spanx> rules as Integration API requests. The
<spanx style="verb">keyid</spanx> MUST identify a key in the Protocol Server's own JWKS, published
at <spanx style="verb">https://<protocol-server-domain>/.well-known/jwks.json</spanx> [RFC7517].
The introspection endpoint MUST verify that the <spanx style="verb">keyid</spanx> domain belongs
to a paired Protocol Server and MUST verify the signature against that
domain's JWKS before evaluating the credential; unauthenticated or
unpaired requests MUST be rejected without revealing whether the
presented credential is valid. This authentication requirement is what
keeps the endpoint from acting as a credential-validity oracle (Section
4 of [RFC7662]).</t>
</section>
<section anchor="response-2"><name>Response</name>
<t>The response is an [RFC7662] introspection response. For an unknown,
expired or revoked credential the endpoint MUST respond with <spanx style="verb">{"active":
false}</spanx> and no other members. For a valid credential the response
object MUST contain:</t>
<t><list style="symbols">
<t><spanx style="verb">active</spanx> (boolean) - <spanx style="verb">true</spanx>.</t>
<t><spanx style="verb">iss</spanx>, <spanx style="verb">sub</spanx>, <spanx style="verb">aud</spanx> (strings) - with the claim semantics this document
defines for access tokens (see Token Issuance by the OCM Server).</t>
<t><spanx style="verb">exp</spanx> (integer) - for a JWT, the token's own <spanx style="verb">exp</spanx>; for a legacy
<spanx style="verb">sharedSecret</spanx>, the time until which the Protocol Server may rely on
this response. The endpoint MUST set a short horizon (on the order of
minutes), since <spanx style="verb">exp</spanx> also bounds revocation latency.</t>
<t><spanx style="verb">client_id</spanx> (string) - the Share's <spanx style="verb">providerId</spanx>, when the Share is
provisioned to the calling Protocol Server.</t>
<t><spanx style="verb">ocm_ip</spanx> (object) - the Share information as defined for the <spanx style="verb">ocm_ip</spanx>
claim, when the Share is not provisioned to the calling Protocol Server.</t>
</list></t>
<t>The Protocol Server uses exactly one of these: a <spanx style="verb">client_id</spanx> naming a
Share Record, or the <spanx style="verb">ocm_ip</spanx> member, as described in Token
Verification.</t>
<t>The Protocol Server MAY cache a positive response until its <spanx style="verb">exp</spanx> and
MUST NOT rely on it beyond that. Negative responses SHOULD NOT be
cached for more than a brief interval.</t>
</section>
</section>
<section anchor="front-channel-resource-access"><name>Front Channel: Resource Access</name>
<section anchor="token-issuance-by-the-ocm-server"><name>Token Issuance by the OCM Server</name>
<t>Token issuance follows the Code Flow of [OCM]: the Receiving Server
exchanges the <spanx style="verb">sharedSecret</spanx> from the Share Creation Notification for an
access token at the OCM Server's <spanx style="verb">tokenEndPoint</spanx>. [OCM] treats the
issued <spanx style="verb">access_token</spanx> as an opaque bearer credential and leaves its
format at the issuer's discretion. This document profiles that format.</t>
<t>For every Share in Provisioned or Self-Contained Integration, the
<spanx style="verb">access_token</spanx> MUST be a JWT conforming to the JWT Profile for OAuth 2.0
Access Tokens [RFC9068]. The JOSE header MUST include <spanx style="verb">typ</spanx> with the
value set to <spanx style="verb">at+jwt</spanx> and MUST include a <spanx style="verb">kid</spanx> parameter identifying the
OCM Server's signatory key advertised in <spanx style="verb">/.well-known/jwks.json</spanx>, and
MUST NOT use <spanx style="verb">none</spanx> as the <spanx style="verb">alg</spanx>. The JWT MUST be signed with the
private key corresponding to that signatory key, allowing anyone with
access to the corresponding public key, including a Protocol Server, to
verify the token independently. The <spanx style="verb">expires_in</spanx> value of the token
response MUST agree with the <spanx style="verb">exp</spanx> claim. Receiving Servers are
unaffected: they continue to treat the token as opaque, per [OCM].</t>
<t>The JWT Claims Set MUST include the claims required by [RFC9068], with
the following OCM-specific semantics, on which the Protocol Server
relies:</t>
<t><list style="symbols">
<t><spanx style="verb">iss</spanx> - the Sending Server identifier, derived from the scheme and
authority of the signatory keyId.</t>
<t><spanx style="verb">sub</spanx> - the Share owner on the Sending Server.</t>
<t><spanx style="verb">aud</spanx> - the OCM principal authorized by the token, i.e. the
<spanx style="verb">shareWith</spanx> value of the Share. Per Section 4.1.3 of [RFC7519] the
interpretation of audience values is application-specific, and this
document defines that interpretation.</t>
<t><spanx style="verb">client_id</spanx> - as defined in Section 4.3 of [RFC8693], which forwards
to Section 2.2 of [RFC6749]. Verifiers MUST NOT assume a particular
size or format beyond what this document specifies per integration
mode.</t>
<t><spanx style="verb">iat</spanx>, <spanx style="verb">exp</spanx>, <spanx style="verb">jti</spanx> - as in [RFC9068].</t>
</list></t>
<t>Further requirements apply per integration mode.</t>
<t>For a Share in Provisioned Integration:</t>
<t><list style="symbols">
<t>The <spanx style="verb">client_id</spanx> claim MUST equal the <spanx style="verb">providerId</spanx> of the Share.</t>
<t>The token MUST NOT carry the <spanx style="verb">ocm_ip</spanx> claim. Mixing the modes for a
single Share would allow a self-contained token to outlive the
revocation of the Share Record (see Security Considerations).</t>
</list></t>
<t>For a Share in Self-Contained Integration:</t>
<t><list style="symbols">
<t>The token MUST carry the <spanx style="verb">ocm_ip</spanx> claim described in the next section.</t>
<t>The <spanx style="verb">exp</spanx> claim MUST NOT be later than the Share's <spanx style="verb">expiration</spanx>, when
the Share has one.</t>
<t>The token SHOULD be short-lived: the RECOMMENDED lifetime is on the
order of minutes or for special use-cases, hours, relying on the
Receiving Server to re-exchange the <spanx style="verb">sharedSecret</spanx> for a fresh token per
[OCM]. Because no revocation signal exists in this mode, the remaining
lifetime of the longest-lived valid token is exactly how long access
survives the end of the Share.</t>
<t>Once the Share ends, the OCM Server MUST NOT issue further tokens for
it. This holds in all modes, but in Self-Contained Integration it is
the only revocation mechanism.</t>
</list></t>
<t>For a Share in Introspected Integration, no additional issuance
requirements apply. Typically no token is issued at all, since this
mode serves Receiving Servers that present the legacy <spanx style="verb">sharedSecret</spanx>
directly. Should such a Share nevertheless be exchanged for tokens, the
Protocol Server can validate those tokens through the same introspection
endpoint.</t>
</section>
<section anchor="the-ocmip-claim"><name>The ocm_ip Claim</name>
<t>The value of the <spanx style="verb">ocm_ip</spanx> claim is a JSON object carrying the Share
information that the Share Provisioning Request carries in Provisioned
Integration. The Share's parties are deliberately not part of the
claim: the owner and the Receiving Party are already bound by the <spanx style="verb">sub</spanx>,
<spanx style="verb">iss</spanx> and <spanx style="verb">aud</spanx> claims of the enclosing token.</t>
<t>Fields:</t>
<t><list style="symbols">
<t>REQUIRED <spanx style="verb">protocol</spanx> (object) - as the <spanx style="verb">protocol</spanx> object of [OCM],
restricted to the protocol entries this token grants access to. It MUST
NOT contain <spanx style="verb">sharedSecret</spanx> fields.</t>
<t>REQUIRED <spanx style="verb">providerId</spanx> (string) - as in [OCM]; opaque identifier of the
Share at the OCM Server, useful for logging and correlation.</t>
<t>REQUIRED <spanx style="verb">resourceType</spanx> (string) - as in [OCM].</t>
<t>OPTIONAL <spanx style="verb">name</spanx> (string) - as in [OCM].</t>
<t>OPTIONAL <spanx style="verb">shareType</spanx> (string) - as in [OCM].</t>
<t>OPTIONAL <spanx style="verb">expiration</spanx> (integer) - as in [OCM].</t>
</list></t>
<t>Fields in the <spanx style="verb">ocm_ip</spanx> claim that the Protocol Server does not
understand MUST be ignored.</t>
</section>
<section anchor="token-verification-by-the-protocol-server"><name>Token Verification by the Protocol Server</name>
<t>When a front-channel request presents a credential, the Protocol Server
MUST authorize it as follows:</t>
<t><list style="numbers" type="1">
<t>If the credential parses as a JWT, extract the <spanx style="verb">iss</spanx> claim without
trusting it; reject the credential if <spanx style="verb">iss</spanx> is missing or is not an
<spanx style="verb">https</spanx> URL, and continue with step 2. If it does not parse as a JWT,
or when the Protocol Server prefers introspection over local
verification, validate the credential through Token Introspection
instead: an <spanx style="verb">active</spanx> response supplies the fields (<spanx style="verb">iss</spanx>, <spanx style="verb">sub</spanx>, <spanx style="verb">aud</spanx>,
<spanx style="verb">exp</spanx>, <spanx style="verb">client_id</spanx>, <spanx style="verb">ocm_ip</spanx>) used in steps 4 to 6, and steps 2 and 3
are skipped; an inactive response means the request is rejected.</t>
<t>Resolve the signing key: fetch (or use a cached copy of) the JWKS at
<spanx style="verb">https://<iss-host>/.well-known/jwks.json</spanx> and select the key matching
the token's <spanx style="verb">kid</spanx> header parameter.</t>
<t>Verify the token signature and validity per [RFC9068]: the algorithm
MUST be an asymmetric algorithm matching the key, MUST NOT be <spanx style="verb">none</spanx>,
and the <spanx style="verb">exp</spanx> claim MUST be in the future. The claims <spanx style="verb">iss</spanx>, <spanx style="verb">sub</spanx>,
<spanx style="verb">aud</spanx>, <spanx style="verb">exp</spanx> and <spanx style="verb">client_id</spanx> MUST all be present.</t>
<t>Determine the integration mode:
<list style="symbols">
<t>If a Share Record exists for the pair (host part of <spanx style="verb">iss</spanx>,
<spanx style="verb">client_id</spanx> claim), the token is authorized against that record
(Provisioned Integration). Any <spanx style="verb">ocm_ip</spanx> claim in the token MUST be
ignored.</t>
<t>Otherwise, if the verified token carries an <spanx style="verb">ocm_ip</spanx> claim and the
host part of <spanx style="verb">iss</spanx> is paired for Self-Contained Integration, or the
introspection response carries an <spanx style="verb">ocm_ip</spanx> member, the credential is
authorized against those claims.</t>
<t>Otherwise, reject the request. Because Share Records only come
into existence through signed back-channel requests from paired OCM
Servers, the <spanx style="verb">ocm_ip</spanx> claim is only honored for paired issuers, and
introspection only ever consults paired endpoints, credentials from