Packages
ash_authentication
3.3.1
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/token_resource/actions.ex
defmodule AshAuthentication.TokenResource.Actions do
@moduledoc """
The code interface for interacting with the token resource.
"""
alias Ash.{Changeset, DataLayer, Query, Resource}
alias AshAuthentication.{TokenResource, TokenResource.Info}
import AshAuthentication.Utils
@doc false
@spec read_expired(Resource.t(), keyword) :: {:ok, [Resource.record()]} | {:error, any}
def read_expired(resource, opts \\ []) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, read_expired_action_name} <- Info.token_read_expired_action_name(resource) do
resource
|> Query.for_read(read_expired_action_name, opts)
|> api.read()
end
end
@doc """
Remove all expired records.
"""
@spec expunge_expired(Resource.t(), keyword) :: :ok | {:error, any}
def expunge_expired(resource, opts \\ []) do
case Info.token_expunge_expired_action_name(resource) do
{:ok, expunge_expired_action_name} ->
resource
|> DataLayer.transaction(
fn -> expunge_inside_transaction(resource, expunge_expired_action_name, opts) end,
nil,
%{
type: :bulk_destroy,
metadata: %{
metadata: %{
resource: resource,
action: expunge_expired_action_name
}
}
}
)
|> case do
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
:error ->
{:error, "No configured expunge_expired_action_name"}
end
end
@doc """
Has the token been revoked?
Similar to `jti_revoked?/2..3` except that it extracts the JTI from the token,
rather than relying on it to be passed in.
"""
@spec token_revoked?(Resource.t(), String.t(), keyword) :: boolean
def token_revoked?(resource, token, opts \\ []) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, is_revoked_action_name} <- Info.token_revocation_is_revoked_action_name(resource) do
resource
|> Query.for_read(is_revoked_action_name, %{"token" => token}, opts)
|> api.read()
|> case do
{:ok, []} -> false
{:ok, _} -> true
_ -> false
end
end
end
@doc """
Has the token been revoked?
Similar to `token-revoked?/2..3` except that rather than extracting the JTI
from the token, assumes that it's being passed in directly.
"""
@spec jti_revoked?(Resource.t(), String.t(), keyword) :: boolean
def jti_revoked?(resource, jti, opts \\ []) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, is_revoked_action_name} <- Info.token_revocation_is_revoked_action_name(resource) do
resource
|> Query.for_read(is_revoked_action_name, %{"jti" => jti}, opts)
|> api.read()
|> case do
{:ok, []} -> false
{:ok, _} -> true
_ -> false
end
end
end
@doc false
@spec valid_jti?(Resource.t(), String.t(), keyword) :: boolean
def valid_jti?(resource, jti, opts \\ []), do: !jti_revoked?(resource, jti, opts)
@doc """
Revoke a token.
Extracts the JTI from the provided token and uses it to generate a revocationr
record.
"""
@spec revoke(Resource.t(), String.t(), keyword) :: :ok | {:error, any}
def revoke(resource, token, opts \\ []) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, revoke_token_action_name} <-
Info.token_revocation_revoke_token_action_name(resource) do
resource
|> Changeset.for_create(
revoke_token_action_name,
%{"token" => token},
Keyword.merge(opts, upsert?: true)
)
|> api.create()
|> case do
{:ok, _} -> :ok
{:error, reason} -> {:error, reason}
end
end
end
@doc """
Store a token.
Stores a token for any purpose.
"""
@spec store_token(Resource.t(), map, keyword) :: :ok | {:error, any}
def store_token(resource, params, opts \\ []) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, store_token_action_name} <- Info.token_store_token_action_name(resource) do
resource
|> Changeset.for_create(
store_token_action_name,
params,
Keyword.merge(opts, upsert?: true)
)
|> api.create()
|> case do
{:ok, _} -> :ok
{:error, reason} -> {:error, reason}
end
end
end
defp expunge_inside_transaction(resource, expunge_expired_action_name, opts) do
with :ok <- assert_resource_has_extension(resource, TokenResource),
{:ok, api} <- Info.token_api(resource),
{:ok, read_expired_action_name} <- Info.token_read_expired_action_name(resource),
query <- Query.for_read(resource, read_expired_action_name, opts),
{:ok, expired} <- api.read(query) do
Enum.reduce_while(expired, :ok, fn record, :ok ->
record
|> Changeset.for_destroy(expunge_expired_action_name, opts)
|> api.destroy()
|> case do
:ok -> {:cont, :ok}
{:error, reason} -> {:halt, {:error, reason}}
end
end)
end
end
end