Phoenix API Toolkit v0.11.0 PhoenixApiToolkit.Security.Plugs View Source
Security-related plugs.
Several of these plugs are based on recommendations for API's by the OWASP guidelines.
Link to this section Summary
Functions
DEPRECATED. Use set_forwarded_ip/2
instead.
Adds security headers to the response as recommended for API's by OWASP. Sets
"x-frame-options": "deny"
and "x-content-type-options": "nosniff"
.
Checks if the request's "content-type"
header is present. Content matching is done by Plug.Parsers
.
Set conn.remote_ip
to the value in header "x-forwarded-for"
, if present.
Check if the JWT in conn.assigns.jwt
has an "aud"
claim that matches the exp_aud
parameter.
This assign is set by PhoenixApiToolkit.Security.Oauth2Plug
and should contain a JOSE.JWT
struct.
Check if the JWT in conn.assigns.jwt
has a "scope"
claim that matches the exp_scopes
parameter.
This assign is set by PhoenixApiToolkit.Security.Oauth2Plug
and should contain a JOSE.JWT
struct.
Link to this section Functions
assign_client_ip(conn, opts \\ [])
View Sourceassign_client_ip(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
DEPRECATED. Use set_forwarded_ip/2
instead.
Assigns the client's IP to the conn as client_ip
. Prefers IP in header "x-forwarded-for"
over
the directly detected remote IP.
Examples
use Plug.Test
def conn_with_ip, do: conn(:get, "/") |> Map.put(:remote_ip, {127, 0, 0, 12})
# by default, the value of `remote_ip` is used
iex> (conn_with_ip() |> assign_client_ip()).assigns.client_ip
"127.0.0.12"
# if header "x-forwarded-for" is set, its value is preferred
iex> (conn_with_ip() |> put_req_header("x-forwarded-for", "10.0.0.1") |> assign_client_ip()).assigns.client_ip
"10.0.0.1"
put_security_headers(conn, opts \\ [])
View Sourceput_security_headers(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
Adds security headers to the response as recommended for API's by OWASP. Sets
"x-frame-options": "deny"
and "x-content-type-options": "nosniff"
.
Examples
use Plug.Test
# it does what it says it does
iex> conn = conn(:get, "/")
iex> put_security_headers(conn).resp_headers -- conn.resp_headers
[{"x-frame-options", "deny"}, {"x-content-type-options", "nosniff"}]
require_content_type(conn, opts \\ [])
View Sourcerequire_content_type(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
Checks if the request's "content-type"
header is present. Content matching is done by Plug.Parsers
.
The filter is only applied to methods which are expected to carry contents, to PUT
, POST
and PATCH
methods, that is. Only one content-type
header is allowed. A noncompliant request causes a
PhoenixApiToolkit.Security.MissingContentTypeError
to be raised,
resulting in a 415 Unsupported Media Type response.
Examples
use Plug.Test
# safe methods pass through
iex> conn = conn(:get, "/")
iex> conn == require_content_type(conn)
true
# compliant unsafe methods (put, post and patch) pass through
iex> conn = conn(:post, "/") |> put_req_header("content-type", "application/json")
iex> conn == require_content_type(conn)
true
# noncompliant unsafe methods cause a MissingContentTypeError to be raised
iex> conn(:post, "/") |> require_content_type()
** (PhoenixApiToolkit.Security.MissingContentTypeError) missing 'content-type' header
set_forwarded_ip(conn, opts \\ [])
View Sourceset_forwarded_ip(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
Set conn.remote_ip
to the value in header "x-forwarded-for"
, if present.
## Examples
use Plug.Test
def conn_with_ip, do: conn(:get, "/") |> Map.put(:remote_ip, {127, 0, 0, 12})
# by default, the value of `remote_ip` is left alone
iex> conn = conn_with_ip() |> set_forwarded_ip()
iex> conn.remote_ip
{127, 0, 0, 12}
# if header "x-forwarded-for" is set, remote ip is overwritten
iex> conn = conn_with_ip() |> put_req_header("x-forwarded-for", "10.0.0.1") |> set_forwarded_ip()
iex> conn.remote_ip
{10, 0, 0, 1}
verify_oauth2_aud(conn, exp_aud)
View Sourceverify_oauth2_aud(Plug.Conn.t(), binary()) :: Plug.Conn.t()
Check if the JWT in conn.assigns.jwt
has an "aud"
claim that matches the exp_aud
parameter.
This assign is set by PhoenixApiToolkit.Security.Oauth2Plug
and should contain a JOSE.JWT
struct.
If not, a PhoenixApiToolkit.Security.Oauth2TokenVerificationError
is raised,
resulting in a 401 Unauthorized response.
Examples
use Plug.Test
def conn_with_aud(aud), do: conn(:get, "/") |> assign(:jwt, %{fields: %{"aud", aud}})
# if aud matches, the conn is passed through
iex> conn = conn_with_aud("my resource server")
iex> conn == conn |> verify_oauth2_aud("my resource server")
true
# an error is raised if aud does not match
iex> conn_with_aud("my resource server") |> verify_oauth2_aud("another server")
** (PhoenixApiToolkit.Security.Oauth2TokenVerificationError) Oauth2 token invalid: aud mismatch
verify_oauth2_scope(conn, exp_scopes)
View Sourceverify_oauth2_scope(Plug.Conn.t(), [binary()]) :: Plug.Conn.t()
Check if the JWT in conn.assigns.jwt
has a "scope"
claim that matches the exp_scopes
parameter.
This assign is set by PhoenixApiToolkit.Security.Oauth2Plug
and should contain a JOSE.JWT
struct.
If not, a PhoenixApiToolkit.Security.Oauth2TokenVerificationError
is raised,
resulting in a 401 Unauthorized response.
Examples
use Plug.Test
def conn_with_scope(scope), do: conn(:get, "/") |> assign(:jwt, %{fields: %{"scope", scope}})
# if there is a matching scope, the conn is passed through
iex> conn = conn_with_scope("admin read:phone")
iex> conn == conn |> verify_oauth2_scope(["admin"])
true
iex> conn == conn |> verify_oauth2_scope(["admin", "not:a:match"])
true
iex> conn == conn |> verify_oauth2_scope(["admin", "read:phone"])
true
# an error is raised if there is no matching scope
iex> conn_with_scope("admin read:phone") |> verify_oauth2_scope(["not:a:match"])
** (PhoenixApiToolkit.Security.Oauth2TokenVerificationError) Oauth2 token invalid: scope mismatch