Packages

UeberauthToken provides an oauth2 token authentication strategy leveraging functionality provided by ueberauth

Current section

Files

Jump to
ueberauth_token lib ueberauth_token.ex
Raw

lib/ueberauth_token.ex

defmodule UeberauthToken do
@moduledoc """
A package for authenticating with an oauth2 token and building an ueberauth struct.
Features:
- Cache the ueberauth struct response using the excellent `whitfin/cachex` library.
- Perform asynchronyous validity checks for each token key in the cache.
See full description of the config options can be found in `UeberauthToken.Config` @moduledoc.
## Defining an provider module
An provider module must be provided in order for UeberauthToken to function correctly. The provider
implements the callbacks specified in the module `UeberauthToken.Strategy`. Read more about the
requirements for the provider in `UeberauthToken.Strategy`.
Read more on basic usage in the `UeberauthToken.Strategy` module.
"""
alias Ueberauth.{Auth, Failure, Strategy}
alias Ueberauth.Failure.Error
alias UeberauthToken.Config
alias Plug.Conn
@token_strategy UeberauthToken.Strategy
@doc """
Execute token validation for an oauth2 bearer token against a
given oauthorization server (provider).
This function may be useful when a token needs to be validated by a resource server
and the validation is taking place outside a `Plug` pipeline. For example, in
a web socket connection.
## Options
* `:validate_provider` - boolean
Defaults to `true`. Validates that the provider has already been configured
in the application configuration. It is recommended to set this
value to `[validate_provider: false]` once it is known that the application
is correctly configured to reduce the runtime burden of checking the
configuration on each token validation event.
## Example usage
@provider UeberauthToken.TestProvider
def connect(%{"authorization" => token} = params, socket) do
case UeberauthToken.token_auth(token, @provider) do
{:ok, %Ueberauth.Auth{} = auth} ->
{:ok, assign(socket, :user_id, auth.uid)}
{:error, %Ueberauth.Failure{} = failure} ->
{:error, failure}
end
end
"""
@spec token_auth(token :: String.t(), provider :: module(), opts :: list()) ::
{:ok, Auth.t()} | {:error, Failure.t()}
def token_auth(token, provider, opts \\ [validate_provider: true])
def token_auth(<<"Bearer ", token::binary>>, provider, opts)
when is_atom(provider) do
with true <- Keyword.get(opts, :validate_provider),
{:ok, :valid} <- Config.validate_provider(provider) do
validate_token(token, provider)
else
false ->
validate_token(token, provider)
{:error, :invalid} ->
invalid_provider_error(provider)
end
end
def token_auth("", provider, _opts) when is_atom(provider) do
empty_token_error(provider)
end
def token_auth(nil, provider, _opts) when is_atom(provider) do
empty_token_error(provider)
end
def token_auth(token, provider, opts) when is_binary(token) and is_atom(provider) do
token_auth("Bearer #{token}", provider, opts)
end
# private
defp parse_ueberauth_struct(%Conn{assigns: %{ueberauth_failure: %Failure{} = auth}}) do
{:error, auth}
end
defp parse_ueberauth_struct(%Conn{assigns: %{ueberauth_auth: %Auth{} = auth}}) do
{:ok, auth}
end
defp invalid_provider_error(provider) do
{:error,
%Failure{
errors: [
%Error{
message: "Invalid provider - #{provider}, ensure the provider ins configured",
message_key: "error"
}
],
provider: provider,
strategy: @token_strategy
}}
end
defp empty_token_error(provider) do
{:error,
%Failure{
errors: [
%Error{
message: "Empty string or null found for token",
message_key: "error"
}
],
provider: provider,
strategy: @token_strategy
}}
end
defp validate_token(token, provider) do
private_fields = %{
provider: provider,
token: %{"authorization" => "Bearer #{token}"}
}
try do
%Conn{}
|> Conn.put_private(:ueberauth_token, private_fields)
|> Strategy.run_callback(@token_strategy)
# ^ leads to invocation of `@token_strategy.handle_callback!/1` and `@token_strategy.auth/1`
|> parse_ueberauth_struct()
rescue
e ->
{:error,
%Failure{
errors: [
%Error{
message: "Failed attempt to verify token due to error: #{inspect(e)}",
message_key: "error"
}
],
provider: provider,
strategy: @token_strategy
}}
end
end
end