apiac_auth_client_jwt v1.1.1 APIacAuthClientJWT View Source

An APIac.Authenticator plug that implements the client authentication part of RFC7523 (JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants).

This method consists in sending a MACed or signed JWT in the request body to the OAuth2 token endpoint, for instance:

POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6IjIyIn0.
eyJpc3Mi[...omitted for brevity...].
cC4hiUPo[...omitted for brevity...]

OpenID Connect further specifies the "client_secret_jwt" and "private_key_jwt" authentication methods (OpenID Connect Core 1.0 incorporating errata set 1 - 9. Client Authentication) refining RFC7523.

Plug options

  • :iat_max_interval: the maximum time interval, in seconds, before a token with an "iat" field is considered too far in the past. Defaults to 30, which means token emitted longer than 30 seconds ago will be rejected
  • :client_callback [mandatory]: a callback that returns client configuration from its client_id. See below for more details
  • error_response_verbosity: one of :debug, :normal or :minimal. Defaults to :normal
  • :protocol: :rfc7523 or :oidc. Defaults to :oidc. When using OpenID Connect, the following additional checks are performed:

    • the "iss" JWT field must be the client id
    • the "jti" claim must be present
  • :jti_register: a module implementing the JTIRegister behaviour, to protect against token replay. Defaults to nil, mandatory if the protocol is set to :oidc
  • :server_metadata_callback [mandatory]: OAuth2 / OpenID Connect server metadata. The following fields are used:

    • "token_endpoint": the "aud" claim of the JWTs must match it
    • "token_endpoint_auth_signing_alg_values_supported": the MAC and signing algorithms supported for verifying JWTs
  • set_error_response: function called when authentication failed. Defaults to send_error_response/3

Options are documented in opts/0.

Client configuration

The client callback returns a map whose keys are those documented in OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 1.

This includes the "client_secret" field that is used for MACed JWTs.

The "token_endpoint_auth_method" is mandatory and must be set to either "client_secret_jwt" or "private_key_jwt".

Determining allowed signature verification algorithms and keys

Signature verification algorithms:

  • if the client's "token_endpoint_auth_signing_alg" is set, use this algorithm if it is allowed by the "token_endpoint_auth_signing_alg_values_supported" server metadata, otherwise, the "token_endpoint_auth_signing_alg_values_supported" value if used
  • then, the client's "token_endpoint_auth_method" is used to filter only relevant algorithms (MAC algorithms if "token_endpoint_auth_method" is set to "client_secret_jwt", signature algorithms otherwise)

Signature verification keys: if "token_endpoint_auth_method" is set to:

  • "client_secret_jwt": both the client's "client_secret" (if present) and "jwks" (if present) fields are used to create the list of suitable MAC verification keys
  • "private_key_jwt": either "jwks" or "jwks_uri" are used to retrieve suitable signature verification keys. Note that both fields should not be configured at the same time

Replay protection

Replay protection can be implemented to prevent a JWT from being reused. This is mandatory when using OpenID Connect.

The :jti_register allows configuring a module that implements the JTIRegister behaviour.

The JTIRegister.ETS implementation provides with a basic implementation for single node servers.

Example

plug APIacAuthClientJWT,
  client_callback: &MyApp.Client.config/1,
  protocol: :rfc7523,
  server_metadata_callback: &MyApp.metadata.get/0

Link to this section Summary

Functions

Saves failure in a Plug.Conn.t/0's private field and returns the conn

Link to this section Types

Link to this type

client_config()

View Source
client_config() :: %{required(String.t()) => any()}
Link to this type

opt()

View Source
opt() ::
  {:iat_max_interval, non_neg_integer()}
  | {:client_callback, (client_id :: String.t() -> client_config())}
  | {:error_response_verbosity, :debug | :normal | :minimal}
  | {:protocol, :rfc7523 | :oidc}
  | {:jti_register, module()}
  | {:server_metadata_callback, (() -> server_metadata())}
  | {:set_error_response,
     (Plug.Conn.t(),
      %APIac.Authenticator.Unauthorized{
        __exception__: term(),
        authenticator: term(),
        reason: term()
      },
      any() ->
        Plug.Conn.t())}
Link to this type

server_metadata()

View Source
server_metadata() :: %{required(String.t()) => any()}

Link to this section Functions

Link to this function

save_authentication_failure_response(conn, error, opts)

View Source
save_authentication_failure_response(
  Plug.Conn.t(),
  %APIac.Authenticator.Unauthorized{
    __exception__: term(),
    authenticator: term(),
    reason: term()
  },
  opts()
) :: Plug.Conn.t()

Saves failure in a Plug.Conn.t/0's private field and returns the conn

See the APIac.AuthFailureResponseData module for more information.