summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2021-09-20 11:25:29 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2021-09-21 22:28:51 +0200
commite910b3ba2ded990a5193f7ea0cfad525332e4171 (patch)
treeb04e74e7c06e0a0fde5edd7ac0b8773db94cd515 /doc
parentdcd329af1ec765ca0fac97ef2dc18a3177d34083 (diff)
JWS: use GOOPS
Diffstat (limited to 'doc')
-rw-r--r--doc/disfluid.texi965
1 files changed, 707 insertions, 258 deletions
diff --git a/doc/disfluid.texi b/doc/disfluid.texi
index 2cfe60c..0047379 100644
--- a/doc/disfluid.texi
+++ b/doc/disfluid.texi
@@ -60,6 +60,7 @@ is tracked in the Guix channel
* Decentralized Authentication on the Web::
* Invoking disfluid::
* Running disfluid with GNU Guix::
+* Managing keys::
* The Json Web Token::
* Caching on server side::
* Content negociation::
@@ -280,264 +281,8 @@ This record configures a server to serve public application pages.
The configuration for the full server.
@end deftp
-@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.
-
-Decoded JWT are represented as a pair. The car of the pair is the
-header, and the cdr is the payload. Both the header and the payload
-use the JSON representation from srfi-180: objects are alists of
-@strong{symbols} to values, arrays are vectors. It is unfortunate that
-guile-json has a slightly different representation, where alist keys
-are @emph{strings}, but we hope that in the future SRFI-180 will be
-more closely respected.
-
-@menu
-* The ID token::
-* The access token::
-* The DPoP proof::
-* Generic JWTs::
-* Public-key cryptography::
-@end menu
-
-@node The ID token
-@section The ID token
-
-The ID token is a special JWT that the application keeps for
-itself. It is signed by the identity provider, and contains the
-following claims:
-
-@table @emph
-@item webid
-the URI of the user’s webid;
-@item iss
-the URI of the identity provider (issuer);
-@item sub
-the username (the webid-oidc issuer puts the webid again here, but it
-could be any string);
-@item aud
-the ID of the client application that is intended to receive the ID
-token;
-@item nonce
-some random data to change the signature;
-@item exp
-an UTC time (in seconds) for when the token expires;
-@item iat
-the time when it was issued.
-@end table
-
-There are functions to work with ID tokens in
-@emph{(webid-oidc oidc-id-token)}.
-
-@deffn function id-token? @var{object}
-Check that @var{object} is a decoded ID token.
-@end deffn
-
-The following helper functions convert URIs to the URIs from
-@emph{(web uri)} and times to @emph{(srfi srfi-19)} dates.
-
-@deffn function id-token-webid @var{token}
-@deffnx function id-token-iss @var{token}
-@deffnx function id-token-sub @var{token}
-@deffnx function id-token-aud @var{token}
-@deffnx function id-token-nonce @var{token}
-@deffnx function id-token-exp @var{token}
-@deffnx function id-token-iat @var{token}
-Get the suitable field from the payload of @var{token}.
-@end deffn
-
-ID tokens can be signed and encoded as a string, or decoded.
-
-@deffn function id-token-decode @var{token} @var{[#http-get]}
-Decode @var{token}, as a string, into a decoded token. The signature
-verification will need to fetch the oidc configuration of the claimed
-issuer, and check the signature against the published keys. The
-@code{http-get} optional keyword argument can set a different
-implementation of @code{http-get} from @emph{(web client)}. Return
-@code{#f} if it failed, or the decoded token otherwise.
-@end deffn
-
-@deffn function id-token-encode @var{token} @var{key}
-Encode @var{token} and sign it with the issuer’s @var{key}.
-@end deffn
-
-@deffn function issue-id-token @var{issuer-key} @var{#:webid} @var{#:iss} @var{#:sub} @var{#:aud} @var{#:validity}
-Create an ID token that is valid for @var{#:validity} seconds, and
-sign and encode it with @var{issuer-key}.
-@end deffn
-
-@node The access token
-@section The access token
-
-The access token is obtained by the client through a token request,
-and is presented to the server on each authenticated request. It is
-signed by the identity provider, and it contains enough information so
-that the server knows who the user is and who the agent is, and most
-importantly the fingerprint of the key that the client should use in a
-DPoP proof.
-
-The API is defined in @emph{(webid-oidc access-token)}.
-
-@deffn function access-token? @var{object}
-Check that @var{object} is a decoded access token.
-@end deffn
-
-There are field getters for the access token:
-
-@deffn function access-token-webid @var{token}
-@deffnx function access-token-iss @var{token}
-@deffnx function access-token-aud @var{token}
-@deffnx function access-token-exp @var{token}
-@deffnx function access-token-iat @var{token}
-@deffnx function access-token-cnf/jkt @var{token}
-@deffnx function access-token-client-id @var{token}
-Get the suitable field from the payload of @var{token}.
-@end deffn
-
-Access tokens can be signed and encoded as a string, or decoded.
-
-@deffn function access-token-decode @var{token} @var{[#http-get]}
-Decode @var{token}, as a string, into a decoded token. As with the ID
-token, the signature verification will need to fetch the oidc
-configuration of the claimed issuer, and check the signature against
-the published keys. The @code{http-get} optional keyword argument can
-set a different implementation of @code{http-get} from
-@emph{(web client)}, for instance to re-use the what has been obtained
-by the ID token validation. Return the decoded access token, or raise
-an exception.
-@end deffn
-
-@deffn function issue-access-token @var{issuer-key} #:@var{webid} #:@var{iss} #:@var{client-id} #:@var{validity} [#:@var{[client-key} | #:@var{cnf/jkt}]
-Create an access token for @var{#:validity} seconds, and encode it
-with @var{issuer-key}. You can either set the @code{#:cnf/jkt} keyword
-argument with the fingerprint of the client key, or set
-@code{#:client-key} directly, in which case the fingerprint will be
-computed for you.
-@end deffn
-
-@node The DPoP proof
-@section The DPoP proof
-
-This is a special JWT, that is signed by a key controlled by the
-application. The access token certifies that the key used to sign the
-proof is approved by the identity provider.
-
-@deffn function dpop-proof? @var{proof}
-Check that the @var{proof} is a decoded DPoP proof. The validity of
-the proof is not checked by this function.
-@end deffn
-
-@deffn function dpop-proof-alg @var{proof}
-@deffnx function dpop-proof-jwk @var{proof}
-@deffnx function dpop-proof-jti @var{proof}
-@deffnx function dpop-proof-htm @var{proof}
-@deffnx function dpop-proof-htu @var{proof}
-@deffnx function dpop-proof-iat @var{proof}
-@deffnx function dpop-proof-ath @var{proof}
-Get the corresponding field of the proof.
-@end deffn
-
-@deffn function dpop-proof-decode @var{method} @var{uri} @var{str} @var{cnf/check} @var{[#:access-token]}
-Check and decode a DPoP proof encoded as @var{str}.
-
-In order to prevent replay attacks, each proof has a unique random
-string that is remembered globally until its expiration date is
-reached.
-
-The proof is limited to the scope of one @var{uri} and one
-@var{method} (@code{'GET}, @code{'POST} and so on).
-
-The key that is used to sign the proof should be confirmed by the
-identity provider. To this end, the @var{cnf/check} function is called
-with the fingerprint of the key. The function should check that the
-fingerprint is OK (return a boolean).
-
-Finally, when the DPoP proof is tied to an access token (so, for all
-uses except requesting an access token or a refresh token), it must be
-bound to an @var{access-token}.
-@end deffn
-
-The DPoP proof algorithm is sensitive to the current time, because the
-proofs have a limited time validity. By default, the time is the
-system time when the proof is decoded.
-
-@deffn parameter current-date
-This parameter overrides the current time.
-
-It is a thunk returning a date, so you need to put two parenthesis to
-get the time. However, you can set it to a date, a time, a number of
-seconds, or a thunk returning any of these.
-
-@example
- (use-module ((webid-oidc parameters) #:prefix p:))
- ;; This is the current date:
- ((p:current-date))
- ;; You can override it with a thunk, or a fixed date:
- (parameterize ((p:current-date 0))
- ;; Jan 1st 1970
- ((p:current-date)))
-@end example
-@end deffn
-
-@deffn function dpop-proof-encode @var{proof} @var{key}
-Encode the proof and sign it with @var{key}. To generate valid proofs,
-@var{key} should be the private key corresponding to the @code{jwk}
-field of the proof.
-@end deffn
-
-@deffn function issue-dpop-proof @var{client-key} #:@var{htm} #:@var{htu} {[#:@var{access-token}=#f]}
-Create a proof, sign it and encode it with
-@var{client-key}. @var{client-key} should contain both the private and
-public key, because the public part is written in the proof and the
-private part is used to sign it. For most uses, the DPoP proof should
-be encoded for a specific access token. Only token requests should
-omit the @samp{access-token} field.
-
-The @samp{iat} field of the DPoP proof is read from the
-@var{current-date} parameter.
-@end deffn
-
-@node Generic JWTs
-@section Generic JWTs
-
-You can parse generic JWTs signed with JWS with the following
-functions from @emph{(webid-oidc jws)}.
-
-@deffn function jws? @var{jwt}
-Check that @var{jwt} is a decoded JWT signed with JWS.
-@end deffn
-
-@deffn function jws-alg @var{jwt}
-Get the algorithm used to sign @var{jwt}.
-@end deffn
-
-@deffn function jws-decode @var{str} @var{lookup-keys}
-Check and decode a JWT signed with JWS and encoded as @var{str}.
-
-Since the decoding and signature verification happen at the same time
-(for user friendliness), the @var{lookup-keys} function is used. It is
-passed as arguments the decoded JWT (but the signature is not checked
-yet), and it should return a public key, a public key set or a list of
-public keys. If the key lookup failed, this function should raise an
-exception.
-@end deffn
-
-@deffn function jws-encode @var{jwt} @var{key}
-Encode the JWT and sign it with @var{key}.
-@end deffn
-
-@node Public-key cryptography
-@section Public-key cryptography
+@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
@@ -713,6 +458,710 @@ If the JWKS cannot be downloaded, or is incorrect, this exception is
raised.
@end deftp
+@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