Current section
Files
Jump to
Current section
Files
lib/ueberauth/strategy/plangrid.ex
defmodule Ueberauth.Strategy.PlanGrid do
@moduledoc """
Provides an Ueberauth strategy for authenticating with PlanGrid.
### Setup
Create an application in PlanGrid for you to use.
Include the provider in your configuration for Ueberauth
config :ueberauth, Ueberauth,
providers: [
plangrid: { Ueberauth.Strategy.PlanGrid, [] }
]
Then include the configuration for PlanGrid.
config :ueberauth, Ueberauth.Strategy.PlanGrid.OAuth,
client_id: System.get_env("PLANGRID_CLIENT_ID"),
client_secret: System.get_env("PLANGRID_CLIENT_SECRET")
"""
use Ueberauth.Strategy, oauth2_module: Ueberauth.Strategy.PlanGrid.OAuth
alias Ueberauth.Auth.{Info, Credentials, Extra}
alias Ueberauth.Strategy.Helpers
@doc """
Handles the initial redirect to the PlanGrid authentication page.
"""
def handle_request!(conn) do
opts = [redirect_uri: redirect_uri(conn)]
module = option(conn, :oauth2_module)
Helpers.redirect!(conn, apply(module, :authorize_url!, [opts]))
end
@doc """
Handles the callback from PlanGrid. When there is a failure from PlanGrid the
failure is included in the `ueberauth_failure` struct. Otherwise the
information returned from PlanGrid is returned in the `Ueberauth.Auth` struct.
"""
def handle_callback!(%Plug.Conn{params: %{"code" => code}} = conn) do
module = option(conn, :oauth2_module)
token = apply(module, :get_token!, [[code: code, redirect_uri: redirect_uri(conn)]])
if token.access_token == nil do
Helpers.set_errors!(conn, [
error(
token.other_params["error"],
token.other_params["error_description"]
)
])
else
fetch_user(conn, token)
end
end
@doc false
def handle_callback!(conn) do
set_errors!(conn, [error("missing_code", "No code received")])
end
@doc """
Cleans up the private area of the connection used for passing the raw PlanGrid
response around during the callback.
"""
def handle_cleanup!(conn) do
conn
|> put_private(:plangrid_user, nil)
|> put_private(:plangrid_token, nil)
end
@doc """
Fetches the uid field from the PlanGrid response. This is the id field for
the user.
"""
def uid(conn) do
conn.private.plangrid_user["id"]
end
@doc """
Includes the credentials from the PlanGrid response.
"""
def credentials(conn) do
token = conn.private.plangrid_token
%Credentials{
token: token.access_token,
refresh_token: token.refresh_token,
expires_at: token.expires_at,
token_type: token.token_type,
expires: !!token.expires_at
}
end
@doc """
Fetches the fields to populate the info section of the `Ueberauth.Auth`
struct.
"""
def info(conn) do
user = conn.private.plangrid_user
%Info{
name: "#{user["first_name"]} #{user["last_name"]}",
first_name: user["first_name"],
last_name: user["last_name"],
email: user["email_address"]
}
end
@doc """
Stores the raw information (including the token) obtained from the PlanGrid
callback.
"""
def extra(conn) do
%Extra{
raw_info: %{
token: conn.private.plangrid_token,
user: conn.private.plangrid_user
}
}
end
defp fetch_user(conn, token) do
conn = put_private(conn, :plangrid_token, token)
with {:ok, user} <- get_me(token) do
put_private(conn, :plangrid_user, user)
else
{:error, :unauthorized} -> set_errors!(conn, [error("token", "unauthorized")])
{:error, %OAuth2.Error{reason: reason}} -> set_errors!(conn, [error("OAuth2", reason)])
{:error, reason} -> set_errors!(conn, [error("OAuth2", reason)])
end
end
defp option(conn, key) do
Keyword.get(Helpers.options(conn), key, Keyword.get(default_options(), key))
end
defp redirect_uri(conn) do
Helpers.callback_url(conn)
end
defp get_me(token) do
headers = [{"accept", "application/vnd.plangrid+json; version=1"}]
case Ueberauth.Strategy.PlanGrid.OAuth.get(token, "/me", headers) do
{:ok, %OAuth2.Response{status_code: 200, body: me}} -> {:ok, me}
{:ok, %OAuth2.Response{status_code: 401, body: _body}} -> {:error, :unauthorized}
_other -> {:error, :no_user}
end
end
end