who_need_help/lib/who_need_help/google_auth.ex

75 lines
2.3 KiB
Elixir

defmodule WhoNeedHelp.GoogleAuth do
@moduledoc """
Provider boundary for Google OpenID Connect authentication.
Provider access and ID tokens are consumed inside the adapter and are never
returned to controllers or persisted by the application.
"""
@type identity :: %{
provider_uid: String.t(),
email: String.t(),
email_verified: true,
display_name: String.t(),
hosted_domain: String.t() | nil
}
@callback enabled?() :: boolean()
@callback authorize_url(String.t()) ::
{:ok, %{url: String.t(), session_params: map()}} | {:error, term()}
@callback callback(String.t(), map(), map()) :: {:ok, identity()} | {:error, term()}
@callback client_id() :: {:ok, String.t()} | {:error, term()}
@callback verify_id_token(String.t(), String.t()) ::
{:ok, identity()} | {:error, term()}
def enabled?, do: adapter().enabled?()
def authorize_url(redirect_uri), do: adapter().authorize_url(redirect_uri)
def callback(redirect_uri, params, session_params),
do: adapter().callback(redirect_uri, params, session_params)
def client_id, do: adapter().client_id()
def verify_id_token(id_token, nonce),
do: adapter().verify_id_token(id_token, nonce)
@doc """
Returns whether Google is authoritative for the identity's current email.
Gmail addresses are hosted by Google. A non-empty hosted-domain claim marks
a verified Google Workspace identity. Other third-party email addresses still
require the user to prove access to the existing local account before linking.
"""
def authoritative_email?(
%{
email: email,
email_verified: true,
hosted_domain: hosted_domain
} = identity
)
when is_binary(email) and is_binary(hosted_domain) do
String.trim(hosted_domain) != "" or authoritative_email?(Map.delete(identity, :hosted_domain))
end
def authoritative_email?(%{
email: email,
email_verified: true
})
when is_binary(email) do
normalized_email = email |> String.trim() |> String.downcase()
String.ends_with?(normalized_email, "@gmail.com")
end
def authoritative_email?(_identity), do: false
defp adapter do
Application.get_env(
:who_need_help,
:google_auth_adapter,
WhoNeedHelp.GoogleAuth.AssentAdapter
)
end
end