Module Webs_kit.Authenticatable

Authenticatable data.

This module defines a simple US-ASCII compatible encoding scheme to publish non-encrypted, expirable data bytes authenticatable with a private key. Human readability and secrecy is a non-goal, storing state in non-trusted environments is.

The data is not encrypted.

Note. The scheme and module is designed with extensibility in mind. But for now only an HMAC-SHA-256 based scheme is defined.

Time

type time = int

The type for some notion of time to expire data. The semantics is left to the client, for example you can use a logical notion of time or the number of seconds since the epoch.

Private keys

type private_key = [
| `Hs256 of string(*

Used with HMAC-SHA-256, hence should be at least 32 bytes.

*)
]

The type for private keys.

val random_private_key_hs256 : ?r:Stdlib.Random.State.t -> unit -> private_key

random_private_key_hs256 () are 64 random bytes sourced from the PRNG r (defaults to Stdlib.Random.make_self_init) initialized PRNG.

val private_key_to_ascii_string : private_key -> string

private_key_to_ascii_string k encodes k to an URL safe US-ASCII scheme that can be read back by private_key_of_string.

val private_key_of_ascii_string : string -> (private_key, string) Stdlib.result

private_key_of_ascii_string s reads back the encoding of private_key_to_string.

Authenticatable

type t = string

The type for authenticatable bytes. The encoding scheme for bytes data and an optional expiration timestamp expire and private key private_key is defined by:

exp = match expire with None -> "" | Some e -> string_of_int e
msg = exp ^ ":" ^ data
hs256 = "HS256:" ^ (hmac_sha_256 private_key msg)
auth = base64url (hs256 ^ msg)

Encode

val encode : private_key:private_key -> expire:time option -> string -> t

encode ~private_key ~expire data makes data data expire at expire (if any) and authenticatable via the private key and scheme defined by private_key.

Decode

type format_error = [
| `Base64url of Webs.Http.Base64.error(*

base64url decode error.

*)
| `Scheme of string option(*

Scheme name, if one was found.

*)
]

The type for decode format errors.

val format_error_message : format_error -> string

format_error_message e is an english error message for e.

type error = [
| `Authentication(*

Authentication error.

*)
| `Expired of time(*

Expiration time.

*)
| `Missing_now_for of time(*

Expiration time.

*)
| `Format of format_error
]

The type for decode and authentication errors. See decode.

val error_message : error -> string

error_message e is an english error message for e.

val error_string : ('aerror) Stdlib.result -> ('a, string) Stdlib.result

error_string r is Result.map_error error_message r.

val decode : private_key:private_key -> now:time option -> t -> (time option * string, error) Stdlib.result

decode ~private_key ~now s authenticates data s with the private key and scheme defined by private_key and expires it (if applicable) according to now. If now is None and s has an expiration timestamp, the result errors. More precisely the the result is:

  • Ok (expire, data) with data the authenticated bytes and expire the expiration timestamp iff s is authenticated by private_key and, if expire is Some t, now is Some n with n < t.
  • Error `Authentication if s cannot be authenticated by private_key.
  • Error (`Expired t), if s is authenticated by private_key and expires at t but now is Some n with n >= t.
  • Error (`Missing_now_for t), if s is authenticated by private_key and expires at t but now is None.
  • Error (`Format _) if any other decoding error occurs.

Untrusted decode

type untrusted = [
| `Untrusted_hs256 of Sha_256.t * time option * string
]

The type for untrusted decode result.

val untrusted_decode : t -> (untrustedformat_error) Stdlib.result

untrusted_decode s decodes the encoding structure of s but neither authenticates nor expires the data.