75 lines
2.3 KiB
Elixir
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
|