Security changes in v0.10

View Source

This release introduces a small but important, and breaking, change to how Oaskit handles security. The goal is to make it easier to build “secure by default” setups when you opt into a security plug.

Summary

  • Oaskit.Plugs.ValidateRequest now always calls the configured :security plug (when present), even if the OpenAPI operation has no security requirements (security: nil).
  • This only affects projects that have configured a :security plug.

Previous behaviour

Before v0.10:

  • If an operation had no security defined and there was no global security requirement, ValidateRequest would not run any security logic for that route.
  • Forgetting to add security to an operation could therefore leave an endpoint unintentionally open.

New behaviour

From v0.10:

  • As soon as you configure a security plug on ValidateRequest, it will run on every request handled with that plug.
  • When an operation has no security defined, the plug receives nil as the :security option and can decide how to handle it.

Deny-by-default with a security plug

One common use case is to treat “no security defined” as “deny access unless explicitly marked as public”.

Here’s a simple example of rejecting any route that hasn’t been explicitly marked as public:

defmodule MyApp.SecurityPlug do
  @behaviour Plug

  @impl true
  def init(opts), do: opts

  @impl true
  def call(conn, opts) do
    case Keyword.fetch!(opts, :security) do
      nil ->
        conn
        |> Conn.send_resp(401, "unauthorized")
        |> Conn.halt()

      requirements ->
        validate_requirements(conn, requirements)
    end
  end

  defp validate_requirements(conn, requirements) do
    # your auth logic here
  end
end

You can invert that logic (treat nil as public, and only enforce checks when requirements are present) if that better matches your application.

Backwards-compatibility

  • If you don’t configure a :security plug in your ValidateRequest options, behaviour is unchanged: routes without security definitions remain accessible.
  • The new behaviour only applies once a security plug is configured, at which point it is invoked for every request.