summaryrefslogtreecommitdiff
path: root/doc/disfluid.texi
blob: fa5347a3413aa8406a80dd3bec1aaf2b16534e1e (plain)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
\input texinfo @c -*-texinfo-*-
@comment $Id@w{$}
@documentlanguage en
@comment %**start of header
@include version.texi
@settitle Demanding Interoperability to Strengthen the Free (Libre) Web: Introducing Disfluid
@syncodeindex pg cp
@syncodeindex fn cp
@syncodeindex vr cp
@syncodeindex tp cp
@comment %**end of header

@copying
This is the manual of disfluid (version @value{VERSION}, @value{UPDATED}), an implementation of the Solid authentication protocol for guile, client and server.

Copyright @copyright{} 2020, 2021 Vivien Kraus
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''
@end quotation
@end copying

@dircategory Software libraries

@direntry
* disfluid: (disfluid)Interoperability on the web
@end direntry

@titlepage
@title Demanding Interoperability to Strengthen the Free (Libre) Web: Introducing Disfluid
@subtitle for version @value{VERSION}, @value{UPDATED}
@author Vivien Kraus (@email{vivien@@planete-kraus.eu})
@page
@vskip 0pt plus 1fill
@insertcopying
@end titlepage

@contents
@ifnottex
@node Top
@top Disfluid
@end ifnottex

Disfluid is an independent implementation of a web stack focusing on
interoperability. In this implementation, the users control what
programs run in their computers. They also choose who to trust for
online data storage and processing, without needing any permission, or
can self-host their data.

The software is available at
@url{https://labo.planete-kraus.eu/webid-oidc.git}. The latest commit
is tracked in the Guix channel
@url{https://labo.planete-kraus.eu/webid-oidc-channel.git}.

@ifnottex
A PDF version of this manual is available at
@url{https://disfluid.planete-kraus.eu/disfluid.pdf}.
@end ifnottex

@menu
* Decentralized Authentication on the Web::
* Invoking disfluid::
* Running disfluid with GNU Guix::
* Common parameters::
* Managing keys::
* OIDC discovery::
* Client manifest::
* The Json Web Token::
* Caching on server side::
* The HTTP Link header::
* Content negociation::
* Server endpoints::
* Running an Identity Provider::
* Running a Resource Server::
* Running a client::
* Serialization to (S)XML::
* Exceptional conditions::
* GNU Free Documentation License::
* Index::
@end menu

@node Decentralized Authentication on the Web
@chapter Decentralized Authentication on the Web

Authentication on the web is currently handled in the following way:
anyone can install a server that will authenticate users on the
web. The problem is interoperability. If a client (an application)
wants to authenticate a user, it has to be approved by the
authentication server. In other words, if @var{useful-program} wants
to authenticate @var{MegaCorp} users, then @var{useful-program} has to
register to @var{MegaCorp} first, and get approved. This goes against
the principle of permission-less innovation, which is at the heart of
the web.

In the decentralized authentication web, the best attempt so far is
that of ActivityPub. All servers are interoperable with respect to
authentication: if user A emits an activity, it is forwarded by A's
server to its recipients, and A's server is responsible for A's
identity.

The problem with that approach is that the data is tied to the
application. It is not possible to use another application to process
the data differently, or to use multiple data sources, in an
interoperable way (without the ActivityPub server knowing). This means
that on Activitypub, microblogging applications will not present
different activities correctly. This also means that it is difficult
to write a free replacement to a non-free application program, because
it would need to manage the data.

In the Solid ecosystem, there is a clear distinction between servers
and applications. An application is free to read data from all places
at the same time, using a permission-less authentication system. Since
the applications do not need to store data, the cost of having users
is neglectible, so users do not need prior approval before using them
(making captchas and the like a thing of the past). Servers do not
have a say in which applications the user uses.

The authentication used is a slight modification of the
well-established OpenID Connect. It is intended to work in a web
browser, but this package demonstrates that it also works without a
web browser.

@node Invoking disfluid
@chapter Invoking disfluid

The @samp{disfluid} program provides different modes of operations:

@table @samp
@item reverse-proxy
Run an authenticating reverse proxy. With this command, you specify a
backend server. When an authenticated user makes a request, you
receive an additional header containing the user’s identity.
@item identity-provider
Run the identity provider only.
@item client-service
The client applications must serve some resources: namely, the client
manifest and the redirect URI.
@item server
Run both an identity provider and a resource server.
@end table

The server is configured with command-line arguments, and environment
variables.

@menu
* General options::
* General server configuration::
* Configuration for the resource server::
* Configuration for the identity provider::
* Configuration for the client service::
@end menu

@node General options
@section General options
The server will respond to @samp{-h} and @samp{-v} commands, to get
the help output and the version information.

The server output (command-line, logs) are localized for the system
administrator. You can control it with the @samp{LANG} environment
variable. So if your locale is not English, you can have the same
commands as in this manual by running with @code{LANG=C}.

The programs respect the @samp{XDG_DATA_HOME} and
@samp{XDG_CACHE_HOME} to store persistent data and disposable
data. The cache directory can be deleted at any time. If one of these
variables is not set, its value is computed from the @samp{HOME}
environment variable.

@node General server configuration
@section General server configuration
All servers are published under the Affero GPL, which means that the
service provider needs to publish all changes made to the program to
users over the network. The @samp{disfluid} command provides a
@samp{--complete-corresponding-source} option so that the system
administrator can specify a means to download the source.

The servers will add a @samp{Source:} header in each response,
containing the value of this configuration option.

The servers can be configured to redirect output and errors to a log
file and an error file, with the @samp{--log-file} and
@samp{--error-file} options.

The server will listen to port 8080 by default, but this may be
configured with @samp{--port}. Since the servers do not support TLS,
and they only support HTTP/1.1, they are intended to run behind a
reverse proxy (even for the authenticating reverse proxy).

Finally, the servers are required to know their public name. This is
configured with the @samp{--server-name} option.

The server will make requests on the world-wide web, for instance to
download client manifests. The requests can be redirected with XML
Catalog, by setting the @samp{XML_CATALOG_FILES} to a space-separated
list of URIs (can be @code{file:} URIs). The requests cannot be
directed to the file system.

@node Configuration for the resource server
@section Configuration for the resource server
The reverse proxy sets an identity header to authenticated
requests. By default, it is @samp{XXX-Agent}, but it can be configured
with @samp{--header}.

The reverse proxy is configured to contact a backend URI with
@samp{--backend-uri}. This backend URI should not be directly exposed,
because a malicious user could set the identity header.

@node Configuration for the identity provider
@section Configuration for the identity provider
The identity provider can only handle one user. If you want to handle
multiple users, it is highly advised to use a different host name for
each user, in case the server is accessed from a web browser. You can
set the identity of the user with @samp{--subject}, and write the
user’s password in a file. Pass the file name with
@samp{--encrypted-password-file}. You can pass the encrypted password
directly with @samp{--encrypted-password}, but the encrypted password
will be public.

The encrypted password format is defined by the crypt function in the
C library. For glibc, it looks like this:
@code{$@var{N}$@var{salt}$@var{hash}}, where @var{N} is the algorithm
identifier, @var{salt} is the password salt annd @var{hash} is its
hash.

The server uses a key, which is not the same thing as the TLS
certificate of the server (remember, the servers don’t support
TLS). It is in the JWK format. You set its file name with
@samp{--key-file}. If the key file does not exist, it will be
generated.

Finally, the public openid configuration requires you to set the JWKS
URI (@samp{--jwks-uri}), authorization endpoint URI
(@samp{--authorization-endpoint-uri}) and token endpoint URI
(@samp{--token-endpoint-uri}). The identity provider will publish the
full URIs, but will respond to their path, regardless of the host.

@node Configuration for the client service
@section Configuration for the client service
The client will serve a stupid page for the redirect URI that will
only display the authorization code. The redirect URI is set with
@samp{--redirect-uri}.

The client ID is set with @samp{--client-id}. This is the URI under
which the client registrationn is served.

Finally, you can set some cosmetic options, but since it can confuse
the user, they are hidden by default by the identity provider.

@table @samp
@item --client-name
set the name of the application.
@item --client-uri
set an URI where to find more information about the client.
@end table

@node Running disfluid with GNU Guix
@chapter Running disfluid with GNU Guix

The channel at
@url{https://labo.planete-kraus.eu/webid-oidc-channel.git} can be used
with guix. It defines the package at the latest commit, and a service
definition in @emph{(vkraus services disfluid)}.

@defvr {service type} disfluid-service-type
This service runs a bunch of disfluid servers with the @emph{disfluid}
system user, each with a unique name. The value it takes is an alist
of service configurations: the keys are unique names (to differenciate
the generated shepherd services), and the values are configuration
records for an issuer, reverse proxy, server, or client service.
@end defvr

@deftp {configuration record} <disfluid-issuer-configuration> [@var{disfluid}] @var{complete-corresponding-source} @var{issuer} @var{key-file} @var{subject} @var{encrypted-password-file} @var{jwks-uri} @var{authorization-endpoint-uri} @var{token-endpoint-uri} @var{port} [@var{extra-options}]
The configuration for the identity provider. The optional
@var{disfluid} argument is the package containing the binary to run,
if you want to apply some patches, and @var{extra-options} is an empty
list by default.
@end deftp

@deftp {configuration record} <disfluid-reverse-proxy-configuration> [@var{disfluid}] @var{complete-corresponding-source} @var{port} @var{inbound-uri} @var{outbound-uri} @var{header} [@var{extra-options}]
This record configures an authenticating reverse proxy.
@end deftp

@deftp {configuration record} <disfluid-client-service-configuration> [@var{disfluid}] @var{complete-corresponding-source} @var{client-id} @var{redirect-uri} [@var{client-name}] [@var{client-uri}] @var{port} [@var{extra-options}]
This record configures a server to serve public application pages.
@end deftp

@deftp {configuration record} <disfluid-server-configuration> [@var{disfluid}] @var{complete-corresponding-source} @var{server-name} @var{key-file} @var{subject} @var{encrypted-password-file} @var{jwks-uri} @var{authorization-endpoint-uri} @var{token-endpoint-uri} @var{port} [@var{extra-options}]
The configuration for the full server.
@end deftp

@node Common parameters
@chapter Common parameters
The @emph{(webid-oidc parameters)} module provides a set of Guile
parameter to control the program behavior.

@deffn {parameter} data-home
This parameter controls the location where the program stores
persistent data. By default, it is located in @code{XDG_DATA_HOME}.
@end deffn

@deffn {parameter} cache-home
This parameter controls the location where the program stores data
that might get deleted at any time. By default, it uses
@code{XDG_CACHE_HOME}.
@end deffn

@deffn {parameter} current-date
This parameter is a thunk similar to SRFI-19 @code{current-date},
except it can be set with a thunk returning a date, time or number of
seconds, or a date, time or number of seconds.
@end deffn

@deffn {parameter} anonymous-http-request
This parameter is a function similar to the @code{http-request}
function in @emph{(web client)}.
@end deffn

@deffn {parameter} authorization-code-default-validity
This parameter controls the number of seconds for which an
authorization code is valid at creation time.
@end deffn

@deffn {parameter} oidc-token-default-validity
This parameter controls the number of seconds for which an ID token or
access token is valid at creation time.
@end deffn

@deffn {parameter} dpop-proof-validity
This parameter controls the number of seconds for which a DPoP proof
is valid after it has been issued.
@end deffn

@node Managing keys
@chapter Managing keys

Some functions require a key, or a key pair, to operate. The
@emph{(webid-oidc jwk)} module provides you with everything required
to manage keys.

@deftp {Class} <private-key> () @var{alg}
This is the base class for a private key. You need it to issue
signatures. Signatures issued with this key will use @var{alg} for the
signature algorithm, but the public key associated with this private
key will verify signatures in any compatible algorithm, not just
@var{alg}.

@var{alg} is a symbol, for instance @code{'RS256}.
@end deftp

@deftp {Class} <public-key> ()
This is the base class for a public key. You need it to check
signatures.
@end deftp

@deftp {Class} <key-pair> () @var{public-key} @var{private-key}
A key pair contains a @var{public-key} and a matching
@var{private-key}. You use this form for keys you own.
@end deftp

@deftp {Class} <rsa-key-pair> () (@code{<key-pair>})
This key pair contains matching RSA keys.
@end deftp

@deftp {Class} <ec-key-pair> () (@code{<key-pair>}) @var{crv}
This key pair contains matching elliptic curve keys. @var{crv} is a
symbol identifiying the curve.
@end deftp

@deftp {Class} <rsa-private-key> (<private-key>) @var{d} @var{p} @var{q} @var{dp} @var{dq} @var{qi}
@deftpx {Class} <rsa-public-key> (<public-key>) @var{n} @var{e}
@deftpx {Class} <ec-scalar> (<private-key>) @var{crv} @var{z}
@deftpx {Class} <ec-point> (<public-key>) @var{crv} @var{x} @var{y}
All fields are strings, base64 encoding the parameters, except
@var{crv}, which is a symbol.
@end deftp

@deftp {Class} <jwks> () @var{keys}
An identity provider may use different keys that are in validity to
sign different access tokens. The JWKS encapsulates many public
@var{keys}.
@end deftp

@deftypefn {Generic method} <public-key> public-key (@var{key} @code{<key-pair>})
@deftypefnx {Generic method} <public-key> public-key (@var{key} @code{<public-key>})
Return the public part of @var{key}, which may either be a key pair or
a public key.
@end deftypefn

@deftypefn {Generic method} <private-key> private-key (@var{key} @code{<key-pair>})
@deftypefnx {Generic method} <private-key> private-key (@var{key} @code{<private-key>})
Return the private part of @var{key}.
@end deftypefn

@deftypefn {Generic method} <string> rsa-d (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-d (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-p (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-p (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-q (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-q (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-dp (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-dp (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-dq (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-dq (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-qi (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-qi (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <string> rsa-n (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-n (@var{key} @code{<rsa-public-key>})
@deftypefnx {Generic method} <string> rsa-e (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <string> rsa-e (@var{key} @code{<rsa-public-key>})
@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-key-pair>})
@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-point>})
@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-scalar>})
@deftypefnx {Generic method} <string> ec-x (@var{key} @code{<ec-key-pair>})
@deftypefnx {Generic method} <string> ec-x (@var{key} @code{<ec-point>})
@deftypefnx {Generic method} <string> ec-y (@var{key} @code{<ec-key-pair>})
@deftypefnx {Generic method} <string> ec-y (@var{key} @code{<ec-point>})
@deftypefnx {Generic method} <string> ec-z (@var{key} @code{<ec-key-pair>})
@deftypefnx {Generic method} <string> ec-z (@var{key} @code{<ec-scalar>})
@deftypefnx {Generic method} <symbol> alg (@var{key} @code{<key-pair>})
@deftypefnx {Generic method} <symbol> alg (@var{key} @code{<private-key>})
Key parameter getters.
@end deftypefn

@deftypefn {Generic method} <list> keys (@var{jwks} @code{<jwks>})
Return all the public keys used by @var{jwks}.
@end deftypefn

@deftypefn {Generic method} <undefined> check-key (@var{key} @code{<public-key>})
@deftypefnx {Generic method} <undefined> check-key (@var{key} @code{<private-key>})
@deftypefnx {Generic method} <undefined> check-key (@var{key} @code{<key-pair>})
Check that the @var{key} parameters are consistent.
@end deftypefn

When exchanging keys, maybe you will have them in the form of a JWK:
an alist from symbols to strings, as a representation for a JSON
object.

@deftypefn {Generic method} <list> key->jwk (@var{key} @code{<public-key>})
@deftypefnx {Generic method} <list> key->jwk (@var{key} @code{<private-key>})
@deftypefnx {Generic method} <list> key->jwk (@var{key} @code{<key-pair>})
Return an alist with known parameter names for JSON.
@end deftypefn

@deffn function jwk->key @var{jwk}
Parse @var{jwk} as a key or a key pair.
@end deffn

@deftypefn {Generic method} <symbol> kty (@var{key} @code{<rsa-key-pair>})
@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<rsa-public-key>})
@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<rsa-private-key>})
@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-key-pair>})
@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-point>})
@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-scalar>})
Return @code{'RSA} for RSA keys, or @code{'EC} for elliptic curve
keys.
@end deftypefn

@deftypefn {Generic method} <string> jkt (@var{key} @code{<key-pair>})
@deftypefnx {Generic method} <string> jkt (@var{key} @code{<public-key>})
Hash the @var{key} parameters in a reproducible order to get the hash
of a key.
@end deftypefn

@deffn function generate-key @var{[#:n-size]} @var{[#:e-size]} @var{[#:e=\"AQAB\"]} @var{[#:crv]}
Generate a new key pair.
@end deffn

@deftypefn {Generic method} <values> serve (@var{jwks} @code{<jwks>}) @var{expiration-date}
Return a response and response body for serving
@var{jwks}. Client-side caching is very much necessary for a JWKS, so
pass @var{expiration-date} as a SRFI-19 date to define a maximum date
for caching. It should be in the future, for instance in 1 hour.
@end deftypefn

@deffn {function} get-jwks @var{uri} [#:@var{http-request}]
Download a JWKS on the web at @var{uri}. Use @var{http-request}, with
the same interface as that of @emph{(web client)}, to actually get the
JWKS.
@end deffn

@deftp {Exception type} &not-a-jwk
If the key parameters are incorrect, this exception is raised.
@end deftp

@deftp {Exception type} &not-a-jwks
If the JWKS cannot be downloaded, or is incorrect, this exception is
raised.
@end deftp

@node OIDC discovery
@chapter OIDC discovery
An identity provider is known by its server name. The different
endpoints can be discovered from there.

@deftp {Class} <oidc-configuration> () @var{jwks-uri} @var{authorization-endpoint} @var{token-endpoint}
The OIDC configuration for an identity provider. @var{jwks-uri},
@var{authorization-endpoint} adn @var{token-endpoint} are all URIs.

You can construct an OIDC configuration two different ways:
@itemize
@item
by passing @code{#:@var{jwks-uri}},
@code{#:@var{authorization-endpoint}} and
@code{#:@var{token-endpoint}} to the constructor;
@item
by passing @code{#:@var{server}}, and optionally
@code{#:@var{http-request}} to the constructor, to query the
@var{server} for its configuration.
@end itemize
@end deftp

@deftp {Exception type} &invalid-oidc-configuration
This exception is raised when the configuration is unusable or
incomplete.
@end deftp

@deffn {function} make-invalid-oidc-configuration
Constructor for the @code{&invalid-oidc-configuration} exception type.
@end deffn

@deffn {function} invalid-oidc-configuration? @var{exception}
Check whether @var{exception} was raised because of an invalid OIDC
configuration.
@end deffn

@deffn {Generic} jwks-uri @var{oidc-configuration}
Return the JWKS uri of @var{oidc-configuration}.
@end deffn

@deffn {Generic} jwks @var{oidc-configuration}
Query the JWKS uri of @var{oidc-configuration}.
@end deffn

@deffn {Generic} authorization-endpoint @var{oidc-configuration}
Return the authorization endpoint of @var{oidc-configuration}.
@end deffn

@deffn {Generic} token-endpoint @var{oidc-configuration}
Return the token endpoint of @var{oidc-configuration}.
@end deffn

@deffn {Generic} serve @var{configuration} @var{expiration-date}
Return 2 values: the response, and response body, needed to serve
@var{configuration}. It is very much recommended to let clients cache
this value. They will not revalidate it until after
@var{expiration-date}, a SRFI-19 date.
@end deffn

@node Client manifest
@chapter Client manifest
To make sure that a client application is legitimate, it is mandated
that it serves a public document under its ID URI, and that document
should confirm the URI and the redirection URI, where the client
application gets the authorization code.

@deftp {Class} <client-manifest> () @var{client-id} @var{redirect-uris}
This is the class encapsulating a very basic client
manifest. @var{client-id} is an URI, and @var{redirect-uris} is a list
of URIs.

You can construct one by providing both @code{#:@var{client-id}} and
@code{#:@var{redirect-uris}}, or by providing only
@code{#:@var{client-id}}, in which case it will be downloaded from the
web.
@end deftp

Clients that cannot serve pages should use the anonymous client ID,
that accepts all redirect URIs.

@deffn {Generic} client-id @var{manifest}
Return the client ID of @var{manifest}.
@end deffn

@deffn {Generic} redirect-uris @var{manifest}
Return the list of accepted redirection URIs for @var{manifest}.
@end deffn

@deffn {Generic} ->json-data @var{manifest}
Convert @var{manifest} to JSON data (alists for objects, vectors for
arrays). You should override this method if you design an extended
client manifest class.
@end deffn

@deffn {Generic} check-redirect-uri @var{manifest} @var{uri}
Check that @var{manifest} controls @var{uri}, where to send the
authorization code. Raises an exception if that’s not the case.
@end deffn

@deftp {Exception type} &invalid-client-manifest
This exception is raised when the client manifest is invalid.
@end deftp

@deffn {function} make-invalid-client-manifest
Constructor for the @code{&invalid-client-manifest} exception type.
@end deffn

@deffn {function} invalid-client-manifest? @var{exception}
Check whether @var{exception} was raised because of an invalid client
manifest.
@end deffn

@deftp {Exception type} &unauthorized-redirect-uri
This exception is raised when the requested authorization URI is
unauthorized.
@end deftp

@deffn {function} make-unauthorized-redirect-uri
Constructor for the @code{&unauthorized-redirect-uri} exception type.
@end deffn

@deffn {function} unauthorized-redirect-uri? @var{exception}
Check whether @var{exception} was raised because of an unauthorized
redirection URI.
@end deffn

@deftp {Exception type} &inconsistent-client-manifest
This exception is raised when the client ID does not match what the
client manifest says.
@end deftp

@deffn {function} make-inconsistent-client-manifest
Constructor for the @code{&inconsistent-client-manifest} exception type.
@end deffn

@deffn {function} inconsistent-client-manifest? @var{exception}
Check whether @var{exception} was raised because of an inconsistent
client manifest.
@end deffn

@deftp {Exception type} &cannot-serve-public-manifest
This exception is raised when the manifest to serve has the public
client URI as ID.
@end deftp

@deffn {function} make-cannot-serve-public-manifest
Constructor for the @code{&cannot-serve-public-manifest} exception type.
@end deffn

@deffn {function} cannot-serve-public-manifest? @var{exception}
Check whether @var{exception} was raised because the server wants to
serve a public manifest.
@end deffn

@deftp {Exception type} &cannot-fetch-client-manifest
This exception is raised when the server does not behave correctly
when fetching the manifest.
@end deftp

@deffn {function} make-cannot-fetch-client-manifest
Constructor for the @code{&cannot-fetch-client-manifest} exception type.
@end deffn

@deffn {function} cannot-fetch-client-manifest? @var{exception}
Check whether @var{exception} was raised because we could not fetch a
client manifest.
@end deffn

@node The Json Web Token
@chapter The Json Web Token

The Json Web Token, or @dfn{JWT}, is a terse representation of a pair
of JSON objects: the @dfn{header}, and the @dfn{payload}. The JWT can
be @dfn{encoded} as a Json Web Signature (@dfn{JWS}), in which case
the header is encoded to base64 with the URL alphabet, and without
padding characters, the payload is also encoded to base64, and the
concatenation of the encoding of the header, a dot, and the encoding
of the payload is signed with some cryptography algorithm. In the
following, we will only be interested by public-key cryptography. The
concatenation of header, dot, payload, dot and signature in base64 is
the encoding of the JWT.

@menu
* Tokens::
* Tokens issued by an OIDC provider::
* Date verification for tokens::
* Single-use tokens::
* ID tokens::
* Access tokens::
* DPoP proofs::
* Authorization codes::
@end menu

@node Tokens
@section Tokens

The @emph{(webid-oidc jws)} implements some functionality for tokens.

@deftp {Class} <token> () @var{alg}
The base class for all tokens. It only knows the signature
@var{alg}orithm. You can construct one in different ways:
@itemize
@item
the @code{#:@var{alg}} construct keyword supports a string or a
keyword as a value, containing a valid JWA identifier, such as
@code{RS256};
@item
the @code{#:@var{signing-key}} keyword defines the key that will serve
to sign the token. The signature algorithm is set to the default of
@var{signing-key};
@item
the @code{#:@var{jwt-header}} and @code{#:@var{jwt-payload}} keywords
let you pass two alists, following the JSON representation from
srfi-180: objects are alists of @strong{symbols} to values, arrays are
vectors.
@end itemize
@end deftp

@deftp {Exception type} &invalid-jws
This exception is raised when a JWT cannot be parsed or constructed as
a JWS.
@end deftp

@deffn {function} make-invalid-jws
Construct an exception of type @code{&invalid-jws}.
@end deffn

@deffn {function} invalid-jws? @var{exception}
Check whether @var{exception} was raised because of an invalid JWS.
@end deffn

There are multiple things you can do with a token.

@deffn {Generic} alg @var{token}
Return the signature algorithm used for @var{token}, as a symbol.
@end deffn

@deffn {Generic} token->jwt @var{token}
Return two alists, following the JSON representation from srfi-180:
one for the header, and then one for the payload.
@end deffn

@deffn {Generic} lookup-keys @var{token} @var{args}
Return the set of keys that could be used to sign @var{token}, as a
public key, a list of keys, or a JWKS. @var{args} is a list of keyword
arguments for specific implementations.
@end deffn

@deffn {Generic} verify @var{token} @var{args}
Suppose that the @var{token} signature has been checked, perform some
additional verifications. This function should raise exceptions to
signal an invalid token.
@end deffn

@deffn {function} decode @var{expected-token-class} @var{encoded} . @var{args}
Parse @var{encoded} as a token from the @var{expected-token-class},
check its signature against the key obtained by @code{(lookup-keys
@var{token} @var{args})} where @var{token} is the parsed token, and
perform additional verifications with @code{(verify @var{token}
@var{args})}.
@end deffn

@deffn {function} encode @var{token} @var{key}
Encode and sign @var{token} with @var{key}, returning a string.
@end deffn

@deffn {function} issue @var{token-class} @var{issuer-key} . @var{args}
Construct a token of @var{token-class} and @var{args} and sign it with
@var{issuer-key}. Since we know the key to sign it, it is not
necessary to pass either @code{#:signing-key} nor @code{#:alg} to the
constructor.
@end deffn

@node Tokens issued by an OIDC provider
@section Tokens issued by an OIDC provider
OIDC tokens are those signed by an OIDC identity provider. This kind
of token knows its issuer, and getting the keys to check the token
signature is done by OIDC discovery.

@deftp {Class} <oidc-token> (<token>) @var{iss}
The base class for tokens which are issued by an identity provider. It
knows the issuer (@var{iss}, an uri from @emph{(web uri)}), and can
query it to check the token signature.

Similarly to the base token type, you can construct one by specifying
its arguments, or create one from a pair of alists.
@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}} is required to
construct the base token;
@item
@code{#:@var{iss}} specifies the issuer.
@end itemize

The main point of this class is to provide a method for the
@code{lookup-keys} generic. This method accepts one keyword argument,
@code{#:@var{http-request}}, a function that behaves like the web
client in @emph{(web client)}. You can set this value as a keyword
argument in the @code{decode} function.
@end deftp

@deffn {Generic} iss @var{token}
Return the issuer of @var{token}, as an URI.
@end deffn

@deftp {Exception type} &cannot-query-identity-provider @var{identity-provider}
This exception is raised when the OIDC discovery
fails. @var{identity-provider} is an URI.
@end deftp

@deffn {function} make-cannot-query-identity-provider @var{identity-provider}
Construct an exception of type @code{&cannot-query-identity-provider}.
@end deffn

@deffn {function} cannot-query-identity-provider? @var{exception}
Check whether @var{exception} was raised because an identity provider
could not be queried.
@end deffn

@deffn {function} cannot-query-identity-provider-value @var{exception}
Return the faulty identity provider for @var{exception}.
@end deffn

@node Date verification for tokens
@section Date verification for tokens
Different kinds of tokens have a requirement for a limited time window
for which the signature should be valid.

@deftp {Class} <time-bound-token> (<token>) @var{iat} @var{exp}
The base class for tokens which are issued for a limited time
window. It knows the issuance date (@var{iat}, a date from
@emph{(srfi srfi-19)}), and the expiration date (@var{iat}, a date
from @emph{(srfi srfi-19)}).

Similarly to the base token type, you can construct one by specifying
its arguments, or create one from a pair of alists.
@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}} is required to
construct the base token;
@item
@code{#:@var{iat}} specifies the issuance date. It defaults to the
current date;
@item
@code{#:@var{exp}} specifies the expiration date. If it is not set,
the value will be computed from @var{iat} and @var{validity};
@item
@code{#:@var{validity}} is used when the expiration date is not known
in advance. It is a number of seconds. For a DPoP proof, the value
should be around 30 seconds. For an access token, a good value is in
the ballpark of 3600 seconds (an hour). Defaults to 3600 seconds, but
be aware that for single-use tokens, this value will be ignored and
replaced with a much shorter time.
@end itemize

The main point of this class is to provide a stricter token validation
function. You can customize the current date by passing
@code{#:@var{current-date} ...} as keyword arguments to
@code{decode}. @code{...} would be replaced with a time or date.
@end deftp

@deffn {Generic} default-validity @var{token}
Return the default validity as a number of seconds to construct
@var{token}, or @code{#f} if an explicit @code{#:validity} is
required.
@end deffn

@deffn {Generic} has-explicit-exp? @var{token}
Check whether we should trust the JWT exp field when constructing
@var{token}. DPoP proofs should not be able to fill our cache with
infinitely-valid proofs, so it is disabled for DPoP proofs.
@end deffn

@deffn {Generic} iat @var{token}
Return the signature date of @var{token}, as a srfi-19 date.
@end deffn

@deffn {Generic} exp @var{token}
Return the expiration date of @var{token}, as a srfi-19 date.
@end deffn

@deftp {Exception type} &signed-in-future @var{signature-date} @var{current-date}
@deftpx {Exception type} &expired @var{expiration-date} @var{current-date}
An exception of type @code{&signed-in-future} is raised when the
current date is before the alleged signature date. Since the signing
entity and the verifier entity may not be on the same system, the
clocks may be slightly out of synchronization, so a margin of 5
seconds is usually accepted.

An exception of type @code{&expired} indicates that the signature is
no longer valid.
@end deftp

@deffn {function} make-signed-in-future @var{signature-date} @var{current-date}
@deffnx {function} make-expired @var{expiration-date} @var{current-date}
Constructors for the @code{&signed-in-future} and @code{&expired}
exception types.
@end deffn

@deffn {function} signed-in-future? @var{exception}
@deffnx {function} expired? @var{exception}
Check whether @var{exception} was raised because of a date mismatch.
@end deffn

@deffn {function} error-signature-date @var{exception}
@deffnx {function} error-expiration-date @var{exception}
@deffnx {function} error-current-date @var{exception}
If @var{exception} was raised because of a date mismatch, return the
signature, expiration or current date.
@end deffn

@node Single-use tokens
@section Single-use tokens
To prevent replay attacks, you might want to assign an unique
identifier to each token of some kind. If you have an expiration date,
you could remember that this identifier has been seen, and forget
about it as soon as the token expires. For this to work, you would
need an expiration date for your single-use token: this is why we only
support it for time-bound tokens, and the validity is reduced down to
2 minutes.

@deftp {Class} <single-use-token> (<time-bound-token>) @var{nonce}
The base class for tokens which are intended to be decoded only
once. The unique identifier string @var{nonce} will be remembered as
long as the program is running and the token is not expired.

Similarly to the base token type, you can construct one by specifying
its arguments, or create one from a pair of alists.
@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}} is required to
construct the base token;
@item
@code{#:@var{iat}} and @code{#:@var{exp}} or @code{#:@var{validity}}
is required to construct the time-bound token;
@item
@code{#:@var{nonce}} specifies the unique identifier. It defaults to a
random string of base64 data encoding 96 bits of entropy.
@item
@end itemize

The main point of this class is to provide an even stricter token
validation function, that can only be run once for a given token (with
reasonable limits: if the program is killed, it won’t remember the
tokens from before). You can customize the current date by passing
@code{#:@var{current-date} ...} as keyword arguments to @code{decode},
just as you do for regular time-bound tokens. @code{...} would be
replaced with a time or date.
@end deftp

@deffn {Generic} nonce-field-name @var{token}
When constructing @var{token} from an existing JWT, this method gives
the field name in the JWT payload that represents the nonce. DPoP
proofs use @code{'jti}, so they override this value.
@end deffn

@deffn {Generic} nonce @var{token}
Return the unique identifier of @var{token}, as a string.
@end deffn

@deftp {Exception type} &nonce-found @var{nonce}
If a token with the same nonce has already been decoded during its
life time, this exception is raised with the duplicated @var{nonce}.
@end deftp

@deffn {function} make-nonce-found @var{nonce}
Construct an exception of type @code{&nonce-found}.
@end deffn

@deffn {function} nonce-found? @var{exception}
Check whether @var{exception} was raised because a single-use token
was already parsed.
@end deffn

@deffn {function} nonce-found-nonce @var{exception}
Return the faulty nonce in @var{exception}.
@end deffn

@node ID tokens
@section ID tokens

The @emph{(webid-oidc oidc-id-token)} module contains a definition for
the OIDC ID token.

@deftp {Class} <id-token> (<single-use-token> <oidc-token>) @var{webid} @var{sub} @var{aud}
The ID token is issued by an identity provider, and is intended to be
used by the client only. It gives information about the user
identified by a @var{webid}, an URI from @emph{(web uri)}, and the
client ID, @var{aud}, an URI too. Since the client should not
communicate this token, it is reasonable to think that the client will
deccode the token as soon as it gets it, and then forget the now
useless signature. This is why this token is considered
single-use. The @var{sub} field should store a username as a string,
but if it is missing, the webid (as a string) will be used.

To construct an ID token, you would either need
@code{#:@var{jwt-header}} and @code{#:@var{jwt-payload}}, as for any
token, or a combination of parameters:

@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}}, to initialize a JWT;
@item
@code{#:@var{iat}} and @code{#:@var{exp}} or @code{#:@var{validity}},
because it is issued for a limited time window (around an hour);
@item
@code{#:@var{nonce}} to define its identifier (defaults to a random
one);
@item
@code{#:@var{iss}}, the issuer URI, because it is an OIDC token;
@item
@code{#:@var{webid}}, an URI identifying the user;
@item
@code{#:@var{sub}}, a string that defaults to the webid;
@item
@code{#:@var{aud}}, an URI identifying the application.
@end itemize
@end deftp

@deffn {Generic} webid @var{token}
Return the user identifier in @var{token}, as an URI.
@end deffn

@deffn {Generic} sub @var{token}
Return the username in @var{token}, as a string.
@end deffn

@deffn {Generic} aud @var{token}
Return the client identifier in @var{token}, as an URI.
@end deffn

@deftp {Exception type} &invalid-id-token
This exception is raised when the ID token is invalid.
@end deftp

@deffn {function} make-invalid-id-token
Construct an exception of type @code{&invalid-id-token}.
@end deffn

@deffn {function} invalid-id-token? @var{exception}
Check whether @var{exception} was raised because of an invalid ID
token.
@end deffn

@node Access tokens
@section Access tokens

The @emph{(webid-oidc access-token)} module contains a definition for
the OIDC access token.

@deftp {Class} <access-token> (<time-bound-token> <oidc-token>) @var{webid} @var{aud} @var{client-id} @var{cnf/jkt}
The access token is issued by an identity provider for a client, and
is intended to be used by the resource servers. It indicates that the
agent possessing a key hashed to @var{cnf/jkt} (a string) is
identified by @var{client-id} (an URI) and is authorized to act on
behalf of the user identified by @var{webid} (an URI). For
compatibility, @var{aud} should be set to the literal string
@code{"solid"}. The agent demonstrates that it owns this key by
issuing a DPoP proof alongside the access token.

To construct an access token, you would either need
@code{#:@var{jwt-header}} and @code{#:@var{jwt-payload}}, as for any
token, or a combination of parameters:

@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}}, to initialize a JWT;
@item
@code{#:@var{iat}} and @code{#:@var{exp}} or @code{#:@var{validity}},
because it is issued for a limited time window (around an hour);
@item
@code{#:@var{iss}}, the issuer URI, because it is an OIDC token;
@item
@code{#:@var{webid}}, an URI identifying the user;
@item
@code{#:@var{client-id}}, an URI identifying the client;
@item
@code{#:@var{cnf/jkt}}, the hash of a public key whose private key is
owned by the client, or @code{#:@var{client-key}}, the client key
itself;
@item
@code{#:@var{aud}}, literally @code{"solid"},
optional, defaults to the correct value.
@end itemize

Since the same access token is presented on each request, it is not
single-use.
@end deftp

@deffn {Generic} webid @var{token}
Return the user identifier in @var{token}, as an URI.
@end deffn

@deffn {Generic} client-id @var{token}
Return the client identifier in @var{token}, as an URI.
@end deffn

@deffn {Generic} cnf/jkt @var{token}
Return the hash of the client key, as a string.
@end deffn

@deffn {Generic} aud @var{token}
Return @code{"solid"}.
@end deffn

@deftp {Exception type} &invalid-access-token
This exception is raised when the access token is invalid.
@end deftp

@deffn {function} make-invalid-access-token
Construct an exception of type @code{&invalid-access-token}.
@end deffn

@deffn {function} invalid-access-token? @var{exception}
Check whether @var{exception} was raised because of an invalid access
token.
@end deffn

@node DPoP proofs
@section DPoP proofs

The @emph{(webid-oidc dpop-proof)} module contains a definition for
the DPoP proof token.

@deftp {Class} <dpop-proof> (<single-use-token>) @var{typ} @var{jwk} @var{htm} @var{htu} @var{ath}
The DPoP proof is a token that is issued by the client, and presented
to the resource server along with an access token. It is only valid
for one request, and for one use. So, it should have a very short
validity frame, for instance 30 seconds, and should only be valid for
a specific request method @var{htm} and a specific request URI
@var{htu}, down to the path, but ignoring the query and fragment.

The DPoP proof is the proof of possession of @var{jwk}, a public
key. It should always have a @var{typ} field set to @code{"dpop+jwt"}.

To construct a DPoP proof, you would either need
@code{#:@var{jwt-header}} and @code{#:@var{jwt-payload}}, as for any
token, or a combination of parameters:

@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}}, to initialize a JWT;
@item
@code{#:@var{iat}} and @code{#:@var{exp}} or @code{#:@var{validity}},
because it is issued for a limited time window (around 30 seconds);
@item
@code{#:@var{nonce}}, because it is single-use;
@item
@code{#:@var{jwk}}, the public key whose possession we demonstrate by
signing the proof;
@item
@code{#:@var{htm}}, the HTTP method used (as a symbol);
@item
@code{#:@var{htu}}, the HTTP URI used (as an URI);
@item
@code{#:@var{ath}}, the hash of the access token that goes with this
proof, or @code{#:@var{access-token}}, the encoded access token
itself, if the proof goes with an access token. Otherwise, pass
@code{#f}. Defaults to @code{#f};
@item
@code{#:@var{typ}}, literally @code{"dpop+jwt"},
optional, defaults to the correct value.
@end itemize

This token class makes a stricter verification function. It requires
you to set as a keyword argument in @code{decode} the following
parameters:

@table @code
@item #:@var{access-token}
set the access token that should go with the proof, defaults to
@code{#f} (no access token);
@item #:@var{method}
set the method used for the proof;
@item #:@var{uri}
set the URI used for the proof;
@item #:@var{cnf/check}
set the expected hash of the key used by the DPoP proof, or a function
taking a public key hash. If this is a function, it should raise an
exception if the hash is invalid, because its return value is ignored.
@end table
@end deftp

@deffn {Generic} jwk @var{proof}
Return the public key whose possession @var{proof} demonstrates.
@end deffn

@deffn {Generic} htm @var{proof}
Return the HTTP method in @var{proof}, as a symbol.
@end deffn

@deffn {Generic} htu @var{proof}
Return the HTTP URI in @var{proof}, as an URI.
@end deffn

@deffn {Generic} ath @var{proof}
Return the hash of the access token that should go with @var{proof},
or @code{#f} if @var{proof} is not used with an access token.
@end deffn

@deffn {Generic} typ @var{proof}
Return @code{"dpop+jwt"}.
@end deffn

@deftp {Exception type} &invalid-dpop-proof
This exception is raised when the DPoP proof is invalid.
@end deftp

@deffn {function} make-invalid-dpop-proof
Construct an exception of type @code{&invalid-dpop-proof}.
@end deffn

@deffn {function} invalid-dpop-proof? @var{exception}
Check whether @var{exception} was raised because of an invalid DPoP
proof.
@end deffn

@deftp {Exception type} &dpop-method-mismatch @var{advertised} @var{actual}
This exception is raised when the @var{advertised} method is not what
is @var{actual}ly used in the request (both symbols).
@end deftp

@deffn {function} make-dpop-method-mismatch @var{advertised} @var{actual}
Construct an exception of type @code{&dpop-method-mismatch}.
@end deffn

@deffn {function} dpop-method-mismatch? @var{exception}
Check whether @var{exception} was raised because of a difference
between the advertised and actual HTTP methods used.
@end deffn

@deffn {function} dpop-method-mismatch-advertised @var{exception}
In case of a DPoP method mismatch causing @var{exception}, return the
method used in the proof signature.
@end deffn

@deffn {function} dpop-method-mismatch-actual @var{exception}
In case of a DPoP method mismatch causing @var{exception}, return the
method that the server received.
@end deffn

@deftp {Exception type} &dpop-uri-mismatch @var{advertised} @var{actual}
This exception is raised when the @var{advertised} URI is not what is
@var{actual}ly used in the request (both URIs).
@end deftp

@deffn {function} make-dpop-uri-mismatch @var{advertised} @var{actual}
Construct an exception of type @code{&dpop-uri-mismatch}.
@end deffn

@deffn {function} dpop-uri-mismatch? @var{exception}
Check whether @var{exception} was raised because of a difference
between the advertised and actual HTTP URIs used.
@end deffn

@deffn {function} dpop-uri-mismatch-advertised @var{exception}
In case of a DPoP URI mismatch causing @var{exception}, return the
URI used in the proof signature.
@end deffn

@deffn {function} dpop-uri-mismatch-actual @var{exception}
In case of a DPoP URI mismatch causing @var{exception}, return the URI
that the server received.
@end deffn

@deftp {Exception type} &dpop-invalid-ath @var{hash} @var{access-token}
This exception is raised when the DPoP proof is intended for use along
with an access token identified by @var{hash}, but is actually used
along with @var{access-token}.
@end deftp

@deffn {function} make-dpop-invalid-ath @var{hash} @var{access-token}
Construct an exception of type @code{&dpop-invalid-ath}.
@end deffn

@deffn {function} dpop-invalid-ath? @var{exception}
Check whether @var{exception} was raised because the DPoP proof was
not used with the correct access token.
@end deffn

@deffn {function} dpop-invalid-ath-hash @var{exception}
In case of a DPoP presented with the wrong access token, causing
@var{exception}, return the hash of the intended access token.
@end deffn

@deffn {function} dpop-invalid-ath-access-token @var{exception}
In case of a DPoP presented with the wrong access token, causing
@var{exception}, return the actual access token.
@end deffn

@deftp {Exception type} &dpop-unconfirmed-key
This exception is raised when the DPoP proof does not demonstrate the
possession of the correct key.
@end deftp

@deffn {function} make-dpop-unconfirmed-key
Construct an exception of type @code{&dpop-unconfirmed-key}.
@end deffn

@deffn {function} dpop-unconfirmed-key? @var{exception}
Check whether @var{exception} was raised because the DPoP proof
demonstrated the possession of an incorrect key.
@end deffn

@node Authorization codes
@section Authorization codes
@emph{(webid-oidc authorization-code)} defines an authorization code
type.

@deftp {Class} <authorization-code> (<single-use-token>) @var{webid} @var{client-id}
While it is not necessary that an authorization code is a JWT, it is
easier to implement that way. It is an authorization for
@var{client-id}, an URI identifying a client, to access the data of
the user identified by @var{webid}, an URI too. It should only be
valid for a limited amount of time, and used once only.


The DPoP proof is a token that is issued by the client, and presented
to the resource server along with an access token. It is only valid
for one request, and for one use. So, it should have a very short
validity frame, for instance 30 seconds, and should only be valid for
a specific request method @var{htm} and a specific request URI
@var{htu}, down to the path, but ignoring the query and fragment.

The DPoP proof is the proof of possession of @var{jwk}, a public
key. It should always have a @var{typ} field set to @code{"dpop+jwt"}.

To construct an authorization code, you would either need
@code{#:@var{jwt-header}} and @code{#:@var{jwt-payload}}, as for any
token, or a combination of parameters:

@itemize
@item
@code{#:@var{alg}} or @code{#:@var{signing-key}}, to initialize a JWT;
@item
@code{#:@var{iat}} and @code{#:@var{exp}} or @code{#:@var{validity}},
because it is issued for a limited time window (around 30 seconds);
@item
@code{#:@var{nonce}}, because it is single-use;
@item
@code{#:@var{webid}}, the user identifier;
@item
@code{#:@var{client-id}}, the client identifier.
@end itemize

The authorization code is signed and verified by the same entity. So,
the key lookup function is tuned to always return the issuer key. You
need to set it as the @code{#:@var{issuer-key}} keyword argument of
the @code{decode} function.
@end deftp

@deffn {Generic} webid @var{token}
Return the user identifier in @var{token}, as an URI.
@end deffn

@deffn {Generic} client-id @var{token}
Return the client identifier in @var{token}, as an URI.
@end deffn

@deftp {Exception type} &invalid-authorization-code
This exception is raised when the authorization ccode is invalid.
@end deftp

@deffn {function} make-invalid-authorization-code
Construct an exception of type @code{&invalid-authorization-code}.
@end deffn

@deffn {function} invalid-authorization-code? @var{exception}
Check whether @var{exception} was raised because of an invalid
authorization code.
@end deffn

@node Caching on server side
@chapter Caching on server side

Both the identity provider and the resource server need to cache
things. The identity provider will cache application webids, and the
resource server will cache the identity provider keys, for instance.

The solution is to use a file-system cache. Every response (except
those that have a cache-control policy of no-store) are stored to a
sub-directory of @emph{XDG_CACHE_HOME}. Each store has a 5% chance of
triggering a cleanup of the cache. When a cleanup occurs, each cached
response has a 5% chance of being dropped, including responses that
are indicated as valid. This way, a malicious cache response that has
a maliciously long validity will not stay too long in the cache. A log
line will indicate which items are dropped.

The @emph{(webid-oidc cache)} module exports two functions to deal
with the cache.

@deffn function clean-cache @var{[#percents]}
Drop @var{percents}% of the cache right now.
@end deffn

@deffn function use-cache @var{f}
Call @var{f} with no arguments, with the default HTTP request method
set to a function that tries to use the cache first.o

The cache will be read and written in the @samp{web-cache}
subdirectory of the cache home. To check the time window validity, the
@var{current-date} parameter is used.

The back-end function, @var{http-get}, defaults to that of
@emph{(web client)}.
@end deffn

@deffn parameter cache-home
This parameters sets the cache directory. By default, it is
@emph{XDG_CACHE_HOME}.
@end deffn

@node The HTTP Link header
@chapter The HTTP Link header
The HTTP Link header lets you attach metadata about a resource,
directly in the HTTP protocol. It is used to link resources to their
auxiliary resources, for instance.

The following API is defined in @emph{(webid-oidc http-link)}:

@deftp {Class} <link> @var{target-iri} @var{relation-type} @var{target-attributes}
The link refers to the @var{target-iri} that is being linked to the
requested resource, with a given @var{relation-type} (a string), and
optional additional @var{target-attributes}.

When constructing a <link>, you should use the
@code{#:@var{target-iri}}, @code{#:@var{relation-type}} and
@code{#:@var{target-attributes}} keyword arguments
(@code{#:@var{target-attributes}} defaults to the empty list) to
initialize the link. For convenience, the @code{#:@var{anchor}},
@code{#:@var{hreflang}}, @code{#:@var{media}}, @code{#:@var{title}},
@code{#:@var{title*}} and @code{#:@var{type}} keyword arguments can be
passed to add well-known target attributes.
@end deftp

@deftp {Class} <target-attribute> @var{key} @var{value}
If you wish to add new extension target attributes, you can create an
ad-hoc target attribute with @var{key} and @var{value} (initialized as
@code{#:@var{key}} and @code{#:@var{value}} constructor keyword
arguments).
@end deftp

@deffn {Generic} target-iri @var{link}
@deffnx {Generic} relation-type @var{link}
@deffnx {Generic} target-attributes @var{link}
Getters for the @code{<link>} class.
@end deffn

@deffn {Generic} key @var{target-attribute}
@deffnx {Generic} value @var{target-attribute}
Getters for the @code{<target-attribute>} class.
@end deffn

@deffn {Generic} target-attribute @var{link} @var{key}
Return the value of the first target attributet with @var{key}.
@end deffn

@deffn {Generic} anchor @var{link}
@deffnx {Generic} hreflang @var{link}
@deffnx {Generic} media @var{link}
@deffnx {Generic} title @var{link}
@deffnx {Generic} title* @var{link}
@deffnx {Generic} type @var{link}
Convenience attribute lookup functions. @code{anchor} returns an URI
referencce, the others return a string.
@end deffn

@deffn {function} declare-link-header!
Declare functions to parse, validate and print HTTP Link headers with
the Guile web request / response API.
@end deffn

@deffn {function} request-links @var{request}
@deffnx {function} response-links @var{response}
Return the list of links in @var{request} or @var{response}.
@end deffn

@node Content negociation
@chapter Content negociation
There are a number of different available syntaxes for RDF, some being
simple and human readable like @emph{turtle}, and others more adapted
to the JavaScript ecosystem like @emph{json-ld}. To help clients both
from and outside of the JS ecosystem, the server needs to perform
@dfn{content negociation}, i.e. convert from one content-type to
another.

@deffn {function from @code{(webid-oidc serve)}} convert @var{client-accepts} @var{server-name} @var{path} @var{content-type} @var{content}
Convert the resource representation under @var{path} on
@var{server-name}, which has a given @var{content-type} and
@var{content}, to a content-type that the @var{client accepts}.

Return 2 values:
@enumerate
@item
the accepted content-type;
@item
the content in the given content-type.
@end enumerate

Currently, the only conversions are from and to @emph{Turtle} and
@emph{N-Quads}.
@end deffn

@node Server endpoints
@chapter Server endpoints

The disfluid server consists of a set of endpoints that handle
requests. The @emph{(webid-oidc server endpoint)} module defines the
base building blocks.

@deftp {Class} <endpoint> () @var{host} @var{path}
All endpoints define a @var{host} for which they are relevant, and an
absolute @var{path}. If a request comes with a matching host and a
matching path prefix, then it will be handled by this endpoint.

If @var{host} is @code{#f}, then this endpoint will be used for all
hosts.

You can construct an endpoint with the @code{#:@var{host}} and
@code{#:@var{path}} keyword arguments: the former is a string
(defaults to @code{#f}), and the latter is a string starting with
@code{"/"} (defaults to @code{"/"}).
@end deftp

@deffn {Generic} handle @var{endpoint} @var{request} @var{request-body}
Handle @var{request} with @var{endpoint}.

@var{request} is the request, in the form of an object from
@emph{(web request)}. @var{request-body} is @code{#f}, a string or a
bytevector.

Return 3 values: a response, a response body (a string, bytevector,
input port, or @code{#f} if no body is expected), and some response
meta-data.
@end deffn

@deffn {Generic} host @var{endpoint}
Return the host name @var{endpoint} is configured to respond to.
@end deffn

@deffn {Generic} path @var{endpoint}
Return the path prefix @var{endpoint} is configured to respond to.
@end deffn

@deffn {Generic} relevant? @var{endpoint} @var{request}
Check if @var{endpoint} is configured to respond to @var{request}.
@end deffn

@menu
* Router endpoint::
@end menu

@node Router endpoint
@section Router endpoint
The first non-trivial handler is for the router endpoint, defined in
@emph{(webid-oidc server endpoint)}.

@deftp {Class} <router> (<endpoint>) @var{routed}
The router has a list of endpoints, and chooses which one will handle
an incoming request based on the request fields. The @var{routed}
endpoints is a list of endpoints. You can set it at construction time
with @code{#:@var{routed}}.

The router will check if the @var{routed} endpoints are relevant, in
turn, or return a 404 Not Found response if no endpoint is relevant.
@end deftp

@deffn {Generic} routed @var{router}
Return the list of endpoints for @var{router}.
@end deffn

@node Running an Identity Provider
@chapter Running an Identity Provider

This project is packaged with a barebones identity provider. It has an
authorization endpoint and a token endpoint (and it serves its public
keys), but it is only intended for one specific person.

You can start it by invoking the @code{webid-oidc} program with the
@code{issuer} command, with the following options:

@table @asis
@item @code{-h}, or @code{--help}
prints a summary of options and exit.
@item @code{-v}, or @code{--version}
prints the version of the program and exits.
@item @code{-n @var{URI}}, or @code{--server-name=@var{URI}}
sets the global server name of the identity provider. It should have
an empty path.
@item @code{-k @var{FILE.jwk}}, or @code{--key-file=@var{FILE.jwk}}
sets the file name where to read or generate a key for the identity
provider. This file should be JSON, containing the representation of a
JWK key pair.
@item @code{-s @var{WEBID}}, or @code{--subject=@var{WEBID}}
sets the webid of the only user of the identity provider. This is an
URI, pointing to a RDF node corresponding to the user’s profile.
@item @code{-w @var{PASSWORD}}, or @code{--password=@var{PASSWORD}}
sets the password that the user must enter to authorize an
application.
@item @code{-j @var{URI}}, or @code{--jwks-uri=@var{URI}}
tells the server that requests to @var{URI} should be responded with
the public key used to sign the tokens.
@item @code{-a @var{URI}}, or @code{--authorization-endpoint-uri=@var{URI}}
tells the server that requests to @var{URI} should be treated as
authorization requests.
@item @code{-t @var{URI}}, or @code{--token-endpoint-uri=@var{URI}}
tells the server that requests to @var{URI} should be treated as token
negociation requests.
@item @code{-p @var{PORT}}, or @code{--port=@var{PORT}}
change the port number used by the server. By default, it is set to
8080.
@item @code{-l @var{FILE.log}}, or @code{--log-file=@var{FILE.log}}
let the server dump all its output to @var{FILE.log}. Since I don’t
know how to deal with syslog, this is the only way to keep logs with a
shepherd service.
@item @code{-e @var{FILE.err}}, or @code{--error-file=@var{FILE.err}}
let the server dump all its errors to @var{FILE.err}.
@end table

The program is sensitive to the environment variables. The most
important one is @emph{LANG}, which influences how the program is
internationalized to the server administrator (the pages served to the
user use the user agent’s locale). This changes the long form of the
options, and the language in the log files.

The @emph{XDG_DATA_HOME} should point to some place where the program
will store refresh tokens, under the @code{webid-oidc} directory. For
a system service, you might want to define that environment to
@code{/var/lib}, for instance.

The @emph{XDG_CACHE_HOME} should point to a directory where to store
the seed of the random number generator (under a @code{webid-oidc}
directory, again). Changing the seed only happens when a program
starts to require the random number generator. You can safely delete
this directory, but you need to restart the program to actually change
the seed.

@node Running a Resource Server
@chapter Running a Resource Server

@menu
* The authenticator::
* The full server::
* Resources stored on the server::
@end menu

A Solid server is the server that manages your data. It needs to check
that the proofs of possession are correct, and the possessed key is
signed by the identity provider.

@node The authenticator
@section The authenticator

In @emph{(webid-oidc resource-server)}, the following function gives a
simple API for a web server:

@deffn function make-authenticator @var{jti-list} @var{[#server-uri]} @var{[#current-time]} @var{[#http-get]}
Create an authenticator, i.e. a function that takes a request and
request body and returns the webid of the authenticated user, or
@code{#f} if it is not authenticated.

To prevent replay attacks, each request is signed by the client with a
different unique padding value. If such a value has already been seen,
then the request must fail.

The authenticator expects the client to demonstrate the possession of
a key that the identity provider knows. So the client creates a DPoP
proof, targetted to a specific URI. In order to check that the URI is
correct, the authenticator needs the public URI of the service.

The JTIs are checked within a small time frame. By default, the system
time will be used. Otherwise, you can customize the
@code{current-time} optional keyword argument, to pass a thunk
returning a time from @emph{(srfi srfi-19)}.

You may want to customize the @var{http-get} optional keyword argument
to pass a function to replace @code{http-get} from @emph{(http
client)}. This function takes an URI and optional @code{#:headers}
arguments, makes the request, and return two values: the response, and
the response body.

This function, in @emph{(webid-oidc resource-server)}, returns a web
request handler, taking the request and request body, and returning
the subject of the access token. If an error happens, it is thrown;
the function always returns a valid URI.
@end deffn

@node The full server
@section The full server

@deffn {function from @emph{(webid-oidc resource-server)}} make-server @var{[#:server-uri]} @var{[#:owner]} @var{[#:authenticator]} @var{[#:current-time]} @var{[#:http-get]}
Return a server handler, a function taking 2 values, a request and a
request body, and returning 2 values, the response and response body.

The optional @var{[#:authenticator]} argument defaults to the
webid-oidc authenticator, @var{[#:current-time]} defaults to a thunk
returning the system time and @var{[#:http-get]} to the web client
from @emph{(web client)}.
@end deffn

@node Resources stored on the server
@section Resources stored on the server

To store and serve resources, the server has two distinct
mechanisms. A @dfn{content} is a read-only possible value for a
resource, indexed by etags, and a @dfn{path} is a mutable value that
indicates the etag of the resource, and of the auxiliary resources
(description and ACL). With this separation, it is possible to
atomically delete a resource and all associated auxiliary resources,
by unlinking the corresponding @emph{path}. It is also possible to
mutate separately the ACL and the resource itself without writing a
copy for both.

The @emph{content} API is contained in the
@code{(webid-oidc server resource content)} module.

@deftp {Class} <content> () @var{etag} @var{content-type} @var{contained} @var{static-content}
This class encapsulate a static resource content linked to a
particular @var{etag}.

The @var{content-type} is a symbol, and @var{static-content} is a
bytevector, although a string will be encoded to UTF-8 at construction
time. @var{contained} is either @code{#f}, if the resource is not a
container, or a list of resource paths (each one is a string)
identifying contained resources.

You can construct a content in two ways.

If you pass @code{#:@var{etag}}, it will be loaded from the file
system under the @var{etag} index, or if @code{#:@var{cache}} is
passed or the @code{current-content-cache} is set to @var{cache}, it
will try to load from @var{cache} first. If you define a cache, the
result will also be added to @var{cache}.

If you pass @code{#:@var{content-type}}, @code{#:@var{contained}} and
@code{#:@var{static-content}}, but not @code{#:etag}, it will be
created and saved to disk, and optionally added to the
@code{#:@var{cache}} or the current content cache.
@end deftp

@deftp {Class} <content-cache> () @var{cache}
Since the contents are read-only, it is possible to cache the values
in memory to avoid reading the same file more than once. This is how
the session works.

@var{cache} is a hash table for string etag values to cached content
values. It is initialized as an empty hash table.
@end deftp

@deffn {Generic} etag @var{content}
Return the ETag of @var{content}, as a string.
@end deffn

@deffn {Generic} content-type @var{content}
Return the Content-Type of @var{content}, as a symbol.
@end deffn

@deffn {Generic} contained @var{content}
Return the contained paths of @var{content}, as a list of strings, or
@code{#f} if it is not a container.
@end deffn

@deffn {Generic} static-content @var{content}
Return the static content of @var{content}, as a bytevector.
@end deffn

@deffn {Generic} delete-content @var{content}
@deffnx {Generic} delete-content @var{etag}
Remove [@var{content}’s] @var{etag} from the file system. If it is
cached in @var{session}, also remove the cached value. Otherwise,
other sessions can still access it.
@end deffn

@deffn parameter current-content-cache
A guile parameter indicating a cache where loaded contents should be
added and preferably fetched. By default, no caching is performed. You
need to set this parameter to benefit from it.
@end deffn

The @emph{path} API is defined in
@code{(webid-oidc server resource path)}.

@deffn function read-path @var{path}
Read the resource at @var{path}, and return 2 values:
@enumerate
@item
the content of the main resource;
@item
an alist where keys are auxiliary resource type URIs (the type is from
@code{(web uri)}), and the values are contents of the corresponding
resource.
@end enumerate

If the resource is not found, raise an exception with type
@code{&path-not-found}, and maybe @code{&uri-slash-semantics-error} if
a resource with a different ending-in-slash exists.

If the @code{current-content-cache} parameter is set to a cache, it
will be used to load the content and auxiliary contents.

This function is safe to call when the path is being modified, either
by another thread, process or else, as the returned values will always
be consistent. However, once the function returns, an updating process
may have deleted the returned content. If this is the case, then you
must call this function again to read the updated path.
@end deffn

@deffn function update-path @var{path} @var{f} [@code{#:@var{create-intermediate-containers?}}=@code{#f}]
Read @var{path}, call @var{f} with two values: the main content and
the auxiliary contents (as returned by @var{read-path}), and update
the path accordingly. If @var{path} does not exist, then the first
argument is @code{#f} and the second one is the empty list.

If @var{f} returns @code{#f}, then the resource is deleted.

If @var{f} returns two values: a content as the first and an alist of
auxiliary types (as URIs) to auxiliary contents as the second, then
the resource is updated.

This function uses the @code{current-content-cache} parameter to load
contents. If a resource is created or deleted, the parent’s
containment triples will be modified, so they will also be loaded in
the cache.

Some operations should create the intermediate containers for a given
path, this is the case for the @code{PUT} HTTP verb. For @code{POST},
the parent should exist. The @var{#:create-intermediate-containers?}
switch lets you change the behavior. In any case, it is an error to
delete a non-empty container.

The update is atomic, meaning that at any point in time the file is
fully written out. Concurrent access to the same resource is performed
by locking the lock file named @var{X}/.lock, where @var{X} is the
first character of the base64-url sha-256 hash of the
path. @strong{The lock file is not meant to be removed} when the
resource is unlocked. It should be locked with @code{flock}
instead. @strong{Like other forms of lock-based synchronization, this
function is not composable}. This means that you cannot call this
function within @var{f}, otherwise a deadlock may ensue.

If the resource is created or deleted, then the parent resource is
updated as well. To avoid deadlocks with other processes, please
follow the following rules: lock the path, then lock the parent path,
then update the parent, then unlock the parent, and finally unlock the
child path.
@end deffn

The Web Access Control specification defines an RDF vocabulary to
check whether a given user is allowed to perform some operations. The
@code{(webid-oidc server resource wac)} helps you do that.

@deffn function wac-get-modes @var{server-name} @var{path} @var{user} @var{[#:http-get]}
Return the list of modes that are allowed for @var{user} accessing
@var{path}. The @var{server-name} URI is required to find the relevant
triples in the ACL. If @var{user} is unauthenticated, pass @code{#f}.

Please note that in any case, the data owner should have all rights
whatsoever, bypassing WAC. Otherwise, it is possible to steal control
away from the data owner.
@end deffn

@deffn function check-acl-can-read @var{server-name} @var{path} @var{owner} @var{user} @var{[#:http-get]}
@deffnx function check-acl-can-write @var{server-name} @var{path} @var{owner} @var{user} @var{[#:http-get]}
@deffnx function check-acl-can-append @var{server-name} @var{path} @var{owner} @var{user} @var{[#:http-get]}
@deffnx function check-acl-can-control @var{server-name} @var{path} @var{owner} @var{user} @var{[#:http-get]}
Assert that the resource at @var{path} on @var{server-name} is owned
by @var{owner}, and check that @var{user} has the proper
authorization. Otherwise, raise an exception of type
@code{&forbidden}.
@end deffn

@node Running a client
@chapter Running a client

The job of the client is to use accounts to fetch private resources on
the web. The @emph{(webid-oidc client)} defines the @code{<client>}
class.

@deftp {Class} <client> @var{client-id} @var{key-pair} @var{redirect-uri}
In OIDC, a client is an application that does not hold the
resources. It may in fact be a network server available on the web, or
a program that you run on your machine. Being a network server or not
is irrelevant.

The @code{<client>} class is designed with immutability in mind. You
can create a client with the @code{make} generic method, using these
keywords to initialize values:

@table @code
@item #:client-id
to set the public client identifier (this endpoint
should be available on the world-wide web), as a string representing
an URI or an URI from @code{(web uri)};
@item #:key-pair
to use a specific key pair. If not set, a new key pair will be
generated;
@item #:redirect-uri
to set the redirect URI that the application controls. It may just be
a page showing the authorization code, with instructions on how to
paste this code into the application. It should match one of the
authorized redirect URIs in the client identifier endpoint.

If you want to set a state parameter for the redirection, you can do
it by setting the guile parameter @code{authorization-state}.
@end table
@end deftp

@deftypefn {Generic method} uri client-id (@var{client} @code{<client>})
@deftypefnx {Generic method} {key pair} key-pair (@var{client} @code{<client>})
@deftypefnx {Generic method} uri redirect-uri (@var{client} @code{<client>})
Slot accessors for @var{client}.
@end deftypefn

@defvr {Parameter} client
Define this parameter to set the client to use to access private data.
@end defvr

To access private data, you must identify yourself. The
@emph{(webid-oidc client accounts)} module lets you define accounts.

@deftp {Class} <account> @var{subject} @var{issuer} @var{id-token} @var{access-token} @var{refresh-token} @var{key-pair}
Encapsulate an account. @var{subject} is your webid, while
@var{issuer} is a host name. @var{id-token} is the @emph{decoded} OIDC ID token, i.e. a
pair of @code{(header . payload)}, because we don’t need to show it to
any other party, so its authenticity needs not be
demonstrated. However, @var{access-token} is an @emph{encoded} access
token (into a string), because we don’t need to worry about its
internals on client side.

There are different ways to initialize an account. First, you can save
all parameters to some form of storage, and restore it by using the
associated keyword arguments at construction time:

@table @code
@item #:subject
@item #:issuer
@item #:id-token
@item #:access-token
@item #:refresh-token
@item #:key-pair
@end table

If you want to make a new account, you would ask the user for an
identity provider, and pass it with @code{#:issuer} as the only
initialized value. The constructor will log you in, using the
@code{authorization-process} and @code{anonymous-http-request}
function parameters.

If you want to refresh an access token, you would also set
@code{#:refresh-token}.

In any case, when you don’t specify a value, it’s as if you passed
@code{#f}.
@end deftp

@defvr {Parameter} authorization-process
This function is called when an explicit user authorization is
required, for instance because there is no refresh token and the
access token expired. The function takes an URI as argument, with an
additional @code{#:reason} keyword argument containing the reason for
the authorization as a string. In this function, you should present
the reason to the user and ask the user to browse this URI so that
your application gets the authorization code.
@end defvr

@defvr {Parameter} anonymous-http-request
This function is used as a back-end for private resource access, and
to query the server configuration. It defaults to @code{http-request}
from @emph{(web client)}.
@end defvr

@deftypefn {Generic method} uri subject (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-subject (@var{account} @code{<account>}) (@var{uri} {string or URI})
@deftypefnx {Generic method} uri issuer (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-issuer (@var{account} @code{<account>}) (@var{uri} {string or URI})
@deftypefnx {Generic method} {optional decoded ID token} id-token (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-id-token (@var{account} @code{<account>}) (@var{id-token} {optional ID token})
@deftypefnx {Generic method} {optional encoded access token} access-token (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-access-token (@var{account} @code{<account>}) (@var{access-token} {optional access token})
@deftypefnx {Generic method} {optional <string>} refresh-token (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-refresh-token (@var{account} @code{<account>}) (@var{refresh-token} {optional <string>})
@deftypefnx {Generic method} {key pair} key-pair (@var{account} @code{<account>})
@deftypefnx {Generic method} <account> set-key-pair (@var{account} @code{<account>}) (@var{key-pair} {optional key pair})
Slot accessors and functional setters for @var{account}.
@end deftypefn

If you intend to run a public network server as a client application,
you may have multiple different users, but you should not let any user
use any account. If this is the case, you can either store the
accounts on the user agent storage (for instance, as a cookie), or
store all of them on the server. If you choose to store the accounts
on the user agent, at least use a new key pair for each of them. If
you want to store the user database on the server side, be aware that
no entity other than yourself will check that your user abides by any
term of service, so it is possible that a single user makes a lot of
accounts to annoy you and fill your hard drive with key pairs. If your
application does not let random people to use it, you might want to
use @emph{protected accounts}, to help you check that the users cannot
impersonate each other.

@deftp {Class} <protected-account> (@code{<account>}) @var{username} @var{encrypted-password}
This superclass of @code{<account>} is protected by a username and
password. It is constructed with the initializer keywords
@code{#:username} and @code{#:encrypted-password}.
@end deftp

@deftypefn {Generic method} <string> username (@var{protected-account} @code{<protected-account>})
@deftypefnx {Generic method} <protected-account> set-username (@var{protected-account} @code{<protected-account>}) (@var{username} <string>)
@deftypefnx {Generic method} <string> encrypted-password (@var{protected-account} @code{<protected-account>})
@deftypefnx {Generic method} <protected-account> set-encrypted-password (@var{protected-account} @code{<protected-account>}) (@var{encrypted-password} <string>)
Slot accessors and functional setters for @var{protected-account}.
@end deftypefn

@deftypefn {Generic method} <account> invalidate-access-token (@var{account} @code{<account>})
Indicate that the access token in @var{account} cannot be used. Before
using @var{account} again, you will need to refresh the access
token. This function does not mutate @var{account}.
@end deftypefn

@deftypefn {Generic method} <account> invalidate-refresh-token (@var{account} @code{<account>})
Indicate that the refresh token has been revoked for
@var{account}. This is usually an indication that the user don’t want
your application to access her private data.  This function does not
mutate @var{account}.
@end deftypefn

@deftypefn {Generic method} <account> refresh (@var{account} @code{<account>})
Refresh the access token.
@end deftypefn

@deftp {Exception type} &authorization-code-required @var{uri}
If the login process requires the user to send an authorization code,
an exception of this type will be raised, with an implicit invitation
for the user to browse @var{uri} and follow the instructions.

The instructions will be handled by the @var{redirect-uri} in the
@code{login} function. If your client is a traditional web
application, the user will be redirected to this URI with an
authorization code. If your client is a native application, then maybe
that redirection URI should display the authorization code and invite
the user to paste it in the appropriate place in the application.

When an exception of this type is raised during the @code{login}
function, it is continuable, meaning that the login function will
resume. You need to create an exception handler for an exception of
this type, look up the @var{uri}, direct the user to browse it, get
the authorization code back, and @emph{return} the authorization code
@emph{from the exception handler}.
@end deftp

@deffn function make-authorization-code-required @var{uri}
@deffnx function authorization-code-required? @var{error}
@deffnx function authorization-code-required-uri @var{error}
Constructor, predicate, and accessor for the
@code{&authorization-code-required} exception type.
@end deffn

@deftp {Exception type} &refresh-token-expired
The refresh token can be used to still perform requests on behalf of
the user when perse is offline. However, if the refresh token expires
while the user is offline, it is not possible to log in again, because
it requires a new authorization code. So, it is not possible to
recover from this error, and the refresh token is immediately
discarded.
@end deftp

@deffn function make-refresh-token-expired
@deffnx function refresh-token-expired? @var{error}
Constructor and predicate for the @code{&refresh-token-expired}
exception type.
@end deffn

@deffn function invalidate-access-token @var{account}
Discard the access token for @var{account}. It is not saved in the
user database yet. This is roughly equivalent to log out.
@end deffn

@deffn function invalidate-refresh-token @var{account}
Discard the refresh token for @var{account}. You still need to save
the @var{account}.
@end deffn

@deftp {Exception type} &token-request-failed @var{response} @var{response-body}
If the token endpoint is unable to deliver an identity token and an
access token, this exception is raised with the identity provider
@var{response} and @var{response body}. This exception cannot be
continued.
@end deftp

@deffn function make-token-request-failed @var{response response-body}
@deffnx function token-request-failed? @var{error}
@deffnx function token-request-response @var{error}
@deffnx function token-request-response-body @var{error}
Constructor, predicate, and accessors for the
@code{&token-request-failed} exception type.
@end deffn

The @emph{(webid-oidc client)} module provides the most useful
function for a client.

@deffn function request @var{account} @var{uri} . @var{args}
Perform a request on behalf of @var{account}, with the current value
of the @var{client} parameter as the client, using as a backend the
current value of @var{anonymous-http-request}.
@end deffn

Finally, to implement your application, there needs to be a public
endpoint for the resource server to check that you are not
impersonating another application. This endpoint can be served by any
web server, but a convenience procedure is made available here:

@deffn function serve-application @var{id} @var{redirect-uri} @var{[#client-name]} @var{[#client-uri]}
Return a handler for web requests to serve the application manifest
and the redirection to transmit the authorization code. You should set
the @var{client-name} to your application name and @var{client-uri} to
point to where to a presentation of your application.
@end deffn

@node Serialization to (S)XML
@chapter Serialization to (S)XML

The @emph{(webid-oidc serializable)} module provides tools to have
serialization to SXML and deserialization from XML.

@deftp {Class} <plugin-class> (<class>) @var{module-name} @var{direct-name}
This metaclass permits to register plugins. @var{module-name} is the
name of a module that defines the class, and @var{direct-name} is the
class name without the surrounding angle brackets. Please note that
all plugin classes should be surrounded by angle brackets.

Most GOOPS classes defined in this program are actually plugin classes.

Serialization works for each slot by serializing other plugin classes
the normal way, and other values are simply represented as strings
with @code{display}.

Deserialization works by loading the module containing the target
class, collecting a value for each slot (a string for
non-plugin-class-valued slots), and making an instance of that class
with all collected values. The initialization function should accept
strings values, for objects that are not of a plugin class.

Since most scheme data types written by @code{display} cannot be read
in a meaningful way, you may add a @code{#:->sxml} slot option with a
function taking the slot value and either returning a string that the
initialization function can parse, or an SXML fragment. For instance,
if a slot should contain an URI value, you would pass @code{#:->sxml
uri->string} as options to the slot definition, and accept a string
value in the initialization function, that you would convert to an URI
with @code{string->uri}.

Sometimes slots contain functional data that cannot be serialized. In
this case, pass @code{#:->sxml 'ignore} to avoid serialization.
@end deftp

@deffn {function} read/xml @var{port}
Read the XML document at @var{port} and deserialize it.
@end deffn

@deffn {function} ->sxml @var{object}
Convert @var{object} to an SXML fragment.
@end deffn

@node Exceptional conditions
@chapter Exceptional conditions

The library will raise an exception whenever something fishy
occurs. For instance, if a signature is invalid, or the expiration
date has passed.

When the client is responsible for an error, such as presenting an
invalid access token, a compound exception is raised. It is sometimes
useful for the user to understand what happened, because it could
indicate a problem in a part of the web they need to change. For
instance, if the access token cannot be decoded because the identity
provider is down, then maybe informing the user of that fact is
useful.

However, presenting too much information is a security risk. For
instance, if the system administrator also runs a private server on
the same machine, and a malicious client tries to pretend that this
private server is an identity provider, then the public server will
try to query the private server. If an error happens and the public
server displays some information to the client, then a part of the
information comes from the private server. Thus, a balance needs to be
found so that not too much is revealed.

The module @emph{(webid-oidc errors)} defines an exception type that
indicates a message that is safe to display to the user.

@deftp {Exception type} &message-for-the-user @var{message}
Indicate that @var{message} can be safely displayed to the user. It is
an XHTML paragraph (or equivalent), presented as SXML.
@end deftp

@deffn function make-message-for-the-user @var{message}
@deffnx user-message @var{exception}
Constructor and accessor for the @code{&message-for-the-user}
exception type.
@end deffn

@node GNU Free Documentation License
@appendix GNU Free Documentation License

@include fdl.texi

@node Index
@unnumbered Index

@printindex cp

@bye