# `Oasis.Token`
[🔗](https://github.com/xinz/oasis/blob/main/lib/oasis/token.ex#L1)

A simple wrapper of `Plug.Crypto` to provide a way to generate and verify bearer token for use
in the [bearer security scheme](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#securitySchemeObject)
of the OpenAPI Specification.

When we use `sign/2` and `verify/2`, the data stored in the token is signed to
prevent tampering but not encrypted, in this scenario, we can store identification information
(such as user NON-PII data), but *SHOULD NOT* be used to store confidential information
(such as credit card numbers, PIN code).

* "NON-PII" means Non Personally Identifiable Information.

If you don't want clients to be able to determine the value of the token, you may use `encrypt/2`
and `decrypt/2` to generate and verify the token.

## Callback

There are two callback functions reserved for use in the generated modules when we use the bearer security
scheme of the OpenAPI Specification.

* `c:crypto_config/2`, provides a way to define the crypto-related key information for the high level usage,
  it required to return an `Oasis.Token.Crypto` struct.
* `c:verify/3`, an optional function to provide a way to custom the verification of the token, you may
  want to use encrypt/decrypt to the token, or other more rules to verify it.

# `opts`

```elixir
@type opts() :: Plug.opts()
```

# `verify_error`

```elixir
@type verify_error() :: {:error, verify_error_status()}
```

Structured verification error returned by `verify/2` and `decrypt/2`.

The second tuple element is a fixed string status code rather than an atom.

# `verify_error_status`

```elixir
@type verify_error_status() :: String.t()
```

String status code used in `verify_error()`.

Allowed values are:

- `"expired"`
- `"invalid"`
- `"missing"`

Elixir typespecs cannot enumerate string literals directly, so this remains
`String.t()` at the type level and the fixed set is documented here.

# `crypto_config`

```elixir
@callback crypto_config(conn :: Plug.Conn.t(), opts :: Keyword.t()) ::
  Oasis.Token.Crypto.t()
```

Avoid using the application enviroment as the configuration mechanism for this library,
and make crypto-related key information configurable when use bearer authentication.

The `Oasis.Plug.BearerAuth` module invokes this callback function to fetch a predefined
`Oasis.Token.Crypto` struct, and then use it to verify the bearer token of the request.

# `verify`
*optional* 

```elixir
@callback verify(conn :: Plug.Conn.t(), token :: String.t(), opts()) ::
  {:ok, term()} | verify_error()
```

An optional callback function to decode the original data from the token, and verify
its integrity.

If we use `sign/2` to create a token, sign it, then provide it to a client application,
the client will then use this token to authenticate requests for resources from the server,
in this scenario, as a common use case, the `Oasis.Plug.BearerAuth` module uses `verify/2`
to finish the verification of the bearer token, so we do not need to implement this
callback function in general.

But if we use `encrypt/2` or other encryption methods to encode, encrypt, and sign data into a token
and send to clients, we need to implement this callback function to custom the way to decrypt
the token and verify its integrity.

# `decrypt`

```elixir
@spec decrypt(crypto :: Oasis.Token.Crypto.t(), token :: String.t()) ::
  {:ok, term()} | verify_error()
```

A wrapper of `Plug.Crypto.decrypt/4` to use `Oasis.Token.Crypto` to decrypt the original data
from the token and verify its integrity, please see `Plug.Crypto.decrypt/4` for details.

Error statuses are normalized to strings (`"expired"`, `"invalid"`) for
Oasis's public callback contract.

# `encrypt`

```elixir
@spec encrypt(crypto :: Oasis.Token.Crypto.t(), data :: term()) :: String.t()
```

A wrapper of `Plug.Crypto.encrypt/4` to use `Oasis.Token.Crypto` to encode, encrypt and
sign data into a token you can send to clients, please see `Plug.Crypto.encrypt/4` for details.

# `random_string`

```elixir
@spec random_string(length :: non_neg_integer()) :: String.t()
```

Generates a random string in N length via `:crypto.strong_rand_bytes/1`.

# `sign`

```elixir
@spec sign(crypto :: Oasis.Token.Crypto.t(), data :: term()) :: String.t()
```

A wrapper of `Plug.Crypto.sign/4` to use `Oasis.Token.Crypto` to sign data
into a token you can send to clients, please see `Plug.Crypto.sign/4` for details.

# `verify`

```elixir
@spec verify(crypto :: Oasis.Token.Crypto.t(), token :: String.t()) ::
  {:ok, term()} | verify_error()
```

A wrapper of `Plug.Crypto.verify/4` to use `Oasis.Token.Crypto` to decode the original
data from the token and verify its integrity, please see `Plug.Crypto.verify/4` for details.

Error statuses are normalized to strings (`"expired"`, `"invalid"`) for
Oasis's public callback contract.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
