Phoenix API Toolkit v0.12.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