Packages
ash_authentication
4.11.0
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash_authentication/strategies/oauth2/sign_in_preparation.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.OAuth2.SignInPreparation do
@moduledoc """
Prepare a query for sign in
Performs three main tasks:
1. Ensures that there is only one matching user record returned, otherwise
returns an authentication failed error.
2. Generates an access token if token generation is enabled.
3. Updates the user identity resource, if one is enabled.
"""
use Ash.Resource.Preparation
alias Ash.{Query, Resource.Preparation}
alias AshAuthentication.{Errors.AuthenticationFailed, Info, Jwt, UserIdentity}
require Ash.Query
import AshAuthentication.Utils, only: [is_falsy: 1]
@doc false
@impl true
@spec prepare(Query.t(), keyword, Preparation.Context.t()) :: Query.t()
def prepare(query, opts, context) do
case Info.find_strategy(query, context, opts) do
:error ->
{:error,
AuthenticationFailed.exception(
strategy: :unknown,
query: query,
caused_by: %{
module: __MODULE__,
action: query.action,
message: "Unable to infer strategy"
}
)}
{:ok, strategy} ->
query
|> Query.after_action(fn
query, [user] ->
with {:ok, user} <- maybe_update_identity(user, query, strategy) do
{:ok, [maybe_generate_token(user, context)]}
end
_, _ ->
{:error,
AuthenticationFailed.exception(
strategy: strategy,
query: query,
caused_by: %{
module: __MODULE__,
action: query.action,
strategy: strategy,
message: "Query should return a single user"
}
)}
end)
end
end
defp maybe_update_identity(user, _query, strategy) when is_falsy(strategy.identity_resource),
do: {:ok, user}
defp maybe_update_identity(user, query, strategy) do
strategy.identity_resource
|> UserIdentity.Actions.upsert(%{
user_info: Query.get_argument(query, :user_info),
oauth_tokens: Query.get_argument(query, :oauth_tokens),
strategy: strategy.name,
user_id: user.id
})
|> case do
{:ok, _identity} ->
user
|> Ash.load(
[
{strategy.identity_relationship_name,
Query.new(strategy.identity_resource)
|> Query.set_context(%{
private: %{
ash_authentication?: true
}
})}
],
domain: Info.domain!(strategy.resource)
)
{:error, reason} ->
{:error, reason}
end
end
defp maybe_generate_token(user, context) do
if AshAuthentication.Info.authentication_tokens_enabled?(user.__struct__) do
{:ok, token, _claims} = Jwt.token_for_user(user, %{}, Ash.Context.to_opts(context))
%{user | __metadata__: Map.put(user.__metadata__, :token, token)}
else
user
end
end
end