AshOaskit.Security (AshOasKit v0.2.0)

View Source

Generates OpenAPI security schemes and requirements for API specifications.

This module provides functions to build security scheme definitions and security requirements that can be applied to operations. It supports common authentication patterns used in JSON:API applications.

Supported Security Schemes

Bearer Token Authentication

HTTP Bearer authentication using JWT or opaque tokens:

%{
  "bearerAuth" => %{
    type: :http,
    scheme: :bearer,
    bearerFormat: "JWT"
  }
}

API Key Authentication

API key passed in header, query, or cookie:

%{
  "apiKeyAuth" => %{
    type: :apiKey,
    in: :header,
    name: "X-API-Key"
  }
}

OAuth2 Authentication

OAuth 2.0 with various flows (authorization code, client credentials, etc.)

OpenID Connect

OpenID Connect Discovery for authentication

Usage

# Build bearer auth security scheme
AshOaskit.Security.bearer_auth_scheme()

# Build security requirement
AshOaskit.Security.security_requirement("bearerAuth")

# Build complete security components
AshOaskit.Security.build_security_schemes([:bearer, :api_key])

Applying Security to Operations

Security can be applied at the spec level (all operations) or per-operation:

# Spec-level security (in generate options)
AshOaskit.spec_31(domains: [MyApp.Blog], security: [%{"bearerAuth" => []}])

# The security schemes are added to components/securitySchemes

Summary

Functions

Adds security to an existing operation schema.

Builds an API Key authentication security scheme.

Builds a Basic authentication security scheme.

Builds a Bearer token authentication security scheme.

Builds a complete security configuration for the spec.

Builds security for an operation based on route configuration.

Builds security schemes based on a list of scheme types.

Builds the securitySchemes component for the OpenAPI spec.

Builds combined security requirements (AND relationship).

Builds the default security requirement for bearer authentication.

Builds an OAuth2 authentication security scheme.

Builds an OpenID Connect authentication security scheme.

Builds an optional security requirement (allows unauthenticated access).

Checks if a route requires authentication based on its configuration.

Builds a security requirement for an operation.

Builds multiple security requirements (OR relationship).

Functions

add_security_to_operation(operation, opts \\ [])

@spec add_security_to_operation(
  map(),
  keyword()
) :: map()

Adds security to an existing operation schema.

Options

  • :security - Security requirement to add. Uses default if not provided.
  • :route - Route configuration to check for public access.

Examples

iex> operation = %{operationId: "getPost", responses: %{}}
...> AshOaskit.Security.add_security_to_operation(operation)
%{
  operationId: "getPost",
  responses: %{},
  security: [%{"bearerAuth" => []}]
}

api_key_scheme(opts \\ [])

@spec api_key_scheme(keyword()) :: map()

Builds an API Key authentication security scheme.

Options

  • :name - Name for the security scheme. Defaults to "apiKeyAuth".
  • :key_name - Name of the API key parameter. Defaults to "X-API-Key".
  • :location - Where the key is passed: :header, :query, or :cookie. Defaults to :header.
  • :description - Description of the scheme.

Examples

iex> AshOaskit.Security.api_key_scheme()
%{
  "apiKeyAuth" => %{
    type: :apiKey,
    in: :header,
    name: "X-API-Key",
    description: "API key authentication"
  }
}

iex> AshOaskit.Security.api_key_scheme(key_name: "api_key", location: :query)
%{
  "apiKeyAuth" => %{
    type: :apiKey,
    in: :query,
    name: "api_key",
    description: "API key authentication"
  }
}

basic_auth_scheme(opts \\ [])

@spec basic_auth_scheme(keyword()) :: map()

Builds a Basic authentication security scheme.

Options

  • :name - Name for the security scheme. Defaults to "basicAuth".
  • :description - Description of the scheme.

Examples

iex> AshOaskit.Security.basic_auth_scheme()
%{
  "basicAuth" => %{
    type: :http,
    scheme: :basic,
    description: "Basic HTTP authentication"
  }
}

bearer_auth_scheme(opts \\ [])

@spec bearer_auth_scheme(keyword()) :: map()

Builds a Bearer token authentication security scheme.

Options

  • :name - Name for the security scheme. Defaults to "bearerAuth".
  • :description - Description of the scheme. Defaults to standard description.
  • :bearer_format - Format of the bearer token (e.g., "JWT"). Defaults to "JWT".

Examples

iex> AshOaskit.Security.bearer_auth_scheme()
%{
  "bearerAuth" => %{
    type: :http,
    scheme: :bearer,
    bearerFormat: "JWT",
    description: "Bearer token authentication"
  }
}

iex> AshOaskit.Security.bearer_auth_scheme(name: "jwtAuth", bearer_format: "JWT")
%{
  "jwtAuth" => %{
    type: :http,
    scheme: :bearer,
    bearerFormat: "JWT",
    description: "Bearer token authentication"
  }
}

build_complete_security_config(opts \\ [])

@spec build_complete_security_config(keyword()) :: map()

Builds a complete security configuration for the spec.

Returns both the security schemes (for components) and the default security requirement (for spec-level security).

Options

  • :schemes - List of scheme types. Defaults to [:bearer].
  • :default_scheme - Name of the default security scheme. Defaults to "bearerAuth".

Examples

iex> AshOaskit.Security.build_complete_security_config(schemes: [:bearer, :api_key])
%{
  schemes: %{"bearerAuth" => %{...}, "apiKeyAuth" => %{...}},
  default_security: [%{"bearerAuth" => []}]
}

build_operation_security(route, opts \\ [])

@spec build_operation_security(
  map(),
  keyword()
) :: [map()] | nil

Builds security for an operation based on route configuration.

Returns nil for public routes, or the default security requirement for authenticated routes.

Options

  • :default_security - Default security requirement to use. Defaults to bearer auth.

Examples

iex> AshOaskit.Security.build_operation_security(%{public?: true})
nil

iex> AshOaskit.Security.build_operation_security(%{public?: false})
[%{"bearerAuth" => []}]

build_security_schemes(scheme_types)

@spec build_security_schemes([atom() | {atom(), keyword()}]) :: map()

Builds security schemes based on a list of scheme types.

Supported Types

  • :bearer - Bearer token authentication
  • :api_key - API key authentication
  • :basic - Basic HTTP authentication
  • :oauth2 - OAuth 2.0 (requires additional configuration)
  • :openid_connect - OpenID Connect (requires URL)

Options

Each scheme type can have its own options passed as a tuple.

Examples

iex> AshOaskit.Security.build_security_schemes([:bearer, :api_key])
%{
  "bearerAuth" => %{...},
  "apiKeyAuth" => %{...}
}

iex> AshOaskit.Security.build_security_schemes([
...>   {:bearer, name: "jwtAuth"},
...>   {:api_key, key_name: "Authorization"}
...> ])

build_security_schemes_component(opts \\ [])

@spec build_security_schemes_component(keyword()) :: map()

Builds the securitySchemes component for the OpenAPI spec.

Options

  • :schemes - List of scheme types to include. Defaults to [:bearer].
  • :custom_schemes - Map of custom security schemes to merge.

Examples

iex> AshOaskit.Security.build_security_schemes_component(schemes: [:bearer, :api_key])
%{
  securitySchemes: %{
    "bearerAuth" => %{...},
    "apiKeyAuth" => %{...}
  }
}

combined_security_requirement(schemes)

@spec combined_security_requirement([String.t() | {String.t(), [String.t()]}]) ::
  map()

Builds combined security requirements (AND relationship).

When multiple schemes are in a single requirement object, ALL must be satisfied.

Examples

iex> AshOaskit.Security.combined_security_requirement(["bearerAuth", "apiKeyAuth"])
%{"bearerAuth" => [], "apiKeyAuth" => []}

default_security_requirement()

@spec default_security_requirement() :: [map()]

Builds the default security requirement for bearer authentication.

This is a convenience function that returns the standard security requirement for bearer token authentication.

Examples

iex> AshOaskit.Security.default_security_requirement()
[%{"bearerAuth" => []}]

oauth2_scheme(opts \\ [])

@spec oauth2_scheme(keyword()) :: map()

Builds an OAuth2 authentication security scheme.

Options

  • :name - Name for the security scheme. Defaults to "oauth2".
  • :description - Description of the scheme.
  • :flows - OAuth2 flows configuration. Required.

Flow Types

  • :authorization_code - Authorization code flow with PKCE
  • :client_credentials - Client credentials flow for machine-to-machine
  • :implicit - Implicit flow (deprecated, not recommended)
  • :password - Resource owner password flow (not recommended)

Examples

iex> AshOaskit.Security.oauth2_scheme(
...>   flows: %{
...>     authorizationCode: %{
...>       authorizationUrl: "https://auth.example.com/authorize",
...>       tokenUrl: "https://auth.example.com/token",
...>       scopes: %{
...>         read: "Read access",
...>         write: "Write access"
...>       }
...>     }
...>   }
...> )

openid_connect_scheme(opts \\ [])

@spec openid_connect_scheme(keyword()) :: map()

Builds an OpenID Connect authentication security scheme.

Options

  • :name - Name for the security scheme. Defaults to "openIdConnect".
  • :description - Description of the scheme.
  • :openid_connect_url - URL to the OpenID Connect discovery document. Required.

Examples

iex> AshOaskit.Security.openid_connect_scheme(
...>   openid_connect_url: "https://auth.example.com/.well-known/openid-configuration"
...> )
%{
  "openIdConnect" => %{
    type: :openIdConnect,
    openIdConnectUrl: "https://auth.example.com/.well-known/openid-configuration",
    description: "OpenID Connect authentication"
  }
}

optional_security(scheme_name, opts \\ [])

@spec optional_security(
  String.t(),
  keyword()
) :: [map()]

Builds an optional security requirement (allows unauthenticated access).

In OpenAPI, an empty object in the security array means the operation can be accessed without authentication.

Examples

iex> AshOaskit.Security.optional_security("bearerAuth")
[%{"bearerAuth" => []}, %{}]

requires_authentication?(route)

@spec requires_authentication?(map()) :: boolean()

Checks if a route requires authentication based on its configuration.

This function checks the route's action for authentication requirements.

Examples

iex> AshOaskit.Security.requires_authentication?(%{action: :read})
true

iex> AshOaskit.Security.requires_authentication?(%{public?: true})
false

security_requirement(scheme_name, opts \\ [])

@spec security_requirement(
  String.t(),
  keyword()
) :: map()

Builds a security requirement for an operation.

Security requirements specify which security schemes apply and what scopes are required (for OAuth2).

Options

  • :scopes - List of required scopes (for OAuth2). Defaults to [].

Examples

iex> AshOaskit.Security.security_requirement("bearerAuth")
%{"bearerAuth" => []}

iex> AshOaskit.Security.security_requirement("oauth2", scopes: ["read", "write"])
%{"oauth2" => ["read", "write"]}

security_requirements(schemes)

@spec security_requirements([String.t() | {String.t(), [String.t()]}]) :: [map()]

Builds multiple security requirements (OR relationship).

When multiple requirements are in a list, the client can use ANY of them.

Examples

iex> AshOaskit.Security.security_requirements(["bearerAuth", "apiKeyAuth"])
[%{"bearerAuth" => []}, %{"apiKeyAuth" => []}]