Packages
ash_authentication
5.0.0-rc.6
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/generate_token_change.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.GenerateTokenChange do
@moduledoc """
Given a successful registration or sign-in, generate a token.
"""
use Ash.Resource.Change
alias Ash.{Changeset, Resource.Change}
alias AshAuthentication.{Info, Jwt}
@doc false
@impl true
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
def change(changeset, options, context) do
changeset
|> Changeset.after_action(fn changeset, result ->
{:ok, strategy} = Info.find_strategy(changeset, context, options)
if Info.authentication_tokens_enabled?(result.__struct__) do
extra_claims = changeset.context[:extra_token_claims] || %{}
generate_token(
changeset.context[:token_type] || :user,
result,
strategy,
context,
extra_claims
)
else
{:ok, result}
end
end)
end
@impl true
def atomic(changeset, options, context) do
{:ok, change(changeset, options, context)}
end
defp generate_token(purpose, record, strategy, context, action_claims)
when is_integer(strategy.sign_in_token_lifetime) and purpose == :sign_in do
opts = Ash.Context.to_opts(context, token_lifetime: strategy.sign_in_token_lifetime)
claims = Map.put(action_claims, "purpose", to_string(purpose))
case Jwt.token_for_user(record, claims, opts, context) do
{:ok, token, _claims} ->
all_extra_claims = merge_dsl_claims(record, action_claims, opts)
{:ok,
record
|> Ash.Resource.put_metadata(:token, token)
|> maybe_put_claims_metadata(all_extra_claims)}
{:error, error} ->
{:error, error}
end
end
defp generate_token(purpose, record, _strategy, context, action_claims) do
opts = Ash.Context.to_opts(context)
claims = Map.put(action_claims, "purpose", to_string(purpose))
case Jwt.token_for_user(record, claims, opts) do
{:ok, token, _claims} ->
all_extra_claims = merge_dsl_claims(record, action_claims, opts)
{:ok,
record
|> Ash.Resource.put_metadata(:token, token)
|> maybe_put_claims_metadata(all_extra_claims)}
{:error, error} ->
{:error, error}
end
end
defp merge_dsl_claims(record, action_claims, opts) do
resource = record.__struct__
dsl_claims =
case Info.authentication_tokens_extra_claims(resource) do
{:ok, extra_claims_fn} when is_function(extra_claims_fn, 2) ->
case extra_claims_fn.(record, opts) do
claims when is_map(claims) -> stringify_keys(claims)
_ -> %{}
end
{:ok, extra_claims} when is_map(extra_claims) ->
stringify_keys(extra_claims)
_ ->
%{}
end
Map.merge(dsl_claims, action_claims)
end
defp stringify_keys(map) when is_map(map) do
Map.new(map, fn {k, v} -> {to_string(k), v} end)
end
defp maybe_put_claims_metadata(record, extra_claims) when map_size(extra_claims) == 0,
do: record
defp maybe_put_claims_metadata(record, extra_claims) do
Ash.Resource.put_metadata(record, :token_claims, extra_claims)
end
end