== User Guide
https://branca.io/[Branca homepage] describes Branca as follows:
[quote]
____
Branca is a secure easy to use token format which makes it hard to shoot
yourself in the foot. It uses IETF XChaCha20-Poly1305 AEAD symmetric encryption
to create encrypted and tamperproof tokens. The encrypted token is base62
encoded which makes it URL safe. Payload itself is an arbitrary sequence of
bytes.
____
clj-branca is a Clojure implementation of encoding and decoding Branca tokens.
It is built on https://docs.lazycode.co/lazysodium/[Lazysodium] cryptography
library.
=== Installation
Add clj-branca to your project's dependencies:
.deps.edn
[source,clojure]
----
{miikka/clj-branca {:mvn/version "0.1.0"}}
----
.Leiningen
[source,clojure]
----
[miikka/clj-branca "0.1.0"]
----
=== Basic usage
The main namespace of clj-branca is `clj-branca.core`. It is recommended to be
required with the alias `branca`.
[source,clojure]
----
(require '[clj-branca.core :as branca])
----
You can encode payload into a token with `branca/encode`. The payload can be a
byte array, a string, or anything else that can be converted into a byte array
by the https://github.com/aleph-io/byte-streams[byte-streams] library. The
tokens is returned as a string.
[source,clojure]
----
(def secret-key "supersecretkeyyoushouldnotcommit")
(def message "Hello, world!")
(branca/encode secret-key message)
;; "XZ69WpRTqZgEOqCJqaOK4iOKGLkg505VSASQ8MMGWs3mn1p6U81FvB5rSLpKlIjkZTUIBC6KiHIboz"
----
To decode the token, use `branca/decode`. It takes the token as a string
and returns the payload as a byte array.
[source,clojure]
----
(String. (branca/decode secret-key "XZ69WpRTqZgEOqCJqaOK4iOKGLkg505VSASQ8MMGWs3mn1p6U81FvB5rSLpKlIjkZTUIBC6KiHIboz"))
;; "Hello, world!"
----
The encryption key used is 32 bytes. It can be a byte array or anything that can
be converted into a byte array. You can generate a new key with
`clj-branca.crypto/generate-key`.
[source,clojure]
----
(require '[clj-branca.crypto])
(clj-branca.crypto/generate-key)
;; #object["[B" 0x7e00ed0f "[B@7e00ed0f"]
----
=== Token timestamp and time to live
Branca tokens contain a timestamp that indicates when the token was issued. To
limit token lifetime, you can give `:ttl` in seconds in the options map when
calling `branca/decode`. For example, to limit token lifetime to an hour:
[source,clojure]
----
(branca/decode secret-key token {:ttl 3600})
----
If the token is expired, `branca/decode` <<error-handling,throws an exception>>.
If you need to implement more complex TTL logic, you can get the token timestamp
as seconds since the Unix epoch along the payload by calling `branca/decode*`.
[source,clojure]
----
(branca/decode* secret-key "XZ69WpRTqZgEOqCJqaOK4iOKGLkg505VSASQ8MMGWs3mn1p6U81FvB5rSLpKlIjkZTUIBC6KiHIboz")
;; {:version -70,
;; :timestamp 1602348074,
;; :nonce #object["[B" 0x37d81587 "[B@37d81587"],
;; :payload #object["[B" 0x7f3e9acc "[B@7f3e9acc"]}
----
The return value includes the token version and the nonce as well. You probably
won't need them for anything, but they're included for the sake of completeness.
TIP: There is only one Branca version, `0xBA`. This is represented as a
single-byte value. Because JVM bytes are _signed_, the value
is printed as `-70` and not as `186` as you might expect.
[[error-handling]]
=== Error handling
Whenever clj-branca encouters an error, such as a malformed or a tampered token,
it throws a `clojure.lang.ExceptionInfo` exception. The exception data contains
the key `:type` to indicate that the exception was thrown by clj-branca.
[options="header""]
|===
| `:type` | explanation
| `:clj-branca.core/invalid-key` | The key must be a 32-byte byte array.
| `:clj-branca.core/encode-failure` | Encryption failed.
| `:clj-branca.core/invalid-token` | Decoding token failed.
|===