Oasis.Plug.BearerAuth (oasis v0.4.0) View Source

Functionality for providing Bearer HTTP authentication.

It is recommended to only use this module in production if SSL is enabled and enforced. See Plug.SSL for more information.

Example

As any other Plug, we can use the bearer_auth/2 plug:

# lib/pre_handler.ex
import Oasis.Plug.BearerAuth

plug :bearer_auth,
  security: Oasis.Gen.BearerAuth
  key_to_assigns: :user_id

# lib/oasis/gen/bearer_auth.ex
defmodule Oasis.Gen.BearerAuth do
  @behaviour Oasis.Token

  @impl true
  def crypto_config(_conn, _options) do
    # return a `Oasis.Token.Crypto` struct in your preferred way
    %Oasis.Token.Crypto{
      secret_key_base: "...",
      salt: "...",
      max_age: 7200
    }
  end
end

Or directly to Oasis.Plug.BearerAuth:

# lib/pre_handler.ex

plug(
  Oasis.Plug.BearerAuth,
  security: Oasis.Gen.BearerAuth,
  key_to_assigns: :user_id
)

# lib/oasis/gen/bearer_auth.ex
defmodule Oasis.Gen.BearerAuth do
  @behaviour Oasis.Token

  @impl true
  def crypto_config(_conn, _options) do
    # ...
  end
end

In general, when we define the bearer security scheme of the OpenAPI Specification in our API design document, for example:

Here, apply the security globally to all operations:

openapi: 3.1.0

components:
  securitySchemes:
    bearerAuth: # arbitrary name for the security scheme
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - bearerAuth: []

Here, apply the security to a operation, and define an optional specification extension "x-oasis-key-to-assigns" field to the :key_to_assigns option of bearer_auth/2:

openapi: 3.1.0

components:
  securitySchemes:
    bearerAuth: # arbitrary name for the security scheme
      type: http
      scheme: bearer
      bearerFormat: JWT
      x-oasis-key-to-assigns: user_id

paths:
  /something:
    get:
      security:
        - bearerAuth: []

The above arbitrary name for the security scheme "bearerAuth" will be transferred into a generated module (see the mentioned "Oasis.Gen.BearerAuth" module) to provide the required crypto-related configuration, and use it as the value to the :security option of bearer_auth/2.

By default, the generated "BearerAuth" module will inherit the module name space in order from the paths object, the operation object if they defined the "x-oasis-name-space" field, or defaults to Oasis.Gen if there are no any specification defined, as an optional, we can add an "x-oasis-name-space" field as a specification extension of the security scheme object to override the module name space, meanwhile, the optional --name-space argument to the mix oas.gen.plug command line is in the highest priority to set the name space of the generated module.

components:
  securitySchemes:
    bearerAuth: # arbitrary name for the security scheme
      type: http
      scheme: bearer
      bearerFormat: JWT
      x-oasis-key-to-assigns: user_id
      x-oasis-name-space: MyToken

In the above example, the final generated module name of "bearerAuth" is MyToken.BearerAuth when there is no --name-space argument input to generate.

After we define bearer authentication into the spec, then run mix oas.gen.plug task with this spec file (via --file argument), there will generate the above similar code to the related module file as long as it does not exist, it also follows the name space definition of the module, and the generation does not override it once the file existed, we need to further edit this file to provide a crypto-related configuration in your preferred way.

If we need a customization to verify the bearer token, we can implement a callback function Oasis.Token.verify/3 to this scenario.

# lib/bearer_auth.ex
defmodule BearerAuth do
  @behaviour Oasis.Token

  @impl true
  def crypto_config(conn, options) do
    %Oasis.Token.Crypto{
      ...
    }
  end

  @impl true
  def verify(conn, token, options) do
    # write your rules to verify the token,
    # and return the expected results in:
    #   {:ok, data}, verified
    #   {:error, :expired}, expired token
    #   {:error, :invalid}, invalid token
  end
end

Link to this section Summary

Functions

Higher level usage of Baerer HTTP authentication.

Callback implementation for Plug.call/2.

Callback implementation for Plug.init/1.

Parses the request token from Bearer HTTP authentication.

Requests bearer authentication from the client.

Link to this section Functions

Link to this function

bearer_auth(conn, options \\ [])

View Source

Higher level usage of Baerer HTTP authentication.

See the module docs for examples.

Options

  • :security, required, a module be with Oasis.Token behaviour.
  • :key_to_assigns, optional, after the verification of the token, the original data will be stored into the conn.assigns once this option defined, for example, if set it as :user_id, we can access the verified data via conn.assigns.user_id in the next plug pipeline.

Callback implementation for Plug.call/2.

Callback implementation for Plug.init/1.

Parses the request token from Bearer HTTP authentication.

It returns either {:ok, token} or {:error, "invalid_request"}.

Link to this function

request_bearer_auth(conn, options \\ [])

View Source

Requests bearer authentication from the client.

It sets the response to status 401 with "Unauthorized" as body. The response is not sent though (nor the connection is halted), allowing developers to further customize it.

A response example:

HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="Application",
                  error="invalid_token",
                  error_description="the access token expired"

Options

  • :realm - the authentication realm. The value is not fully sanitized, so do not accept user input as the realm and use strings with only alphanumeric characters and space.
  • :error - an optional tuple to represent "error" and "error_description" attributes, for example, {"invalid_token", "the access token expired"}