mirror of
https://github.com/team-alembic/ash_authentication.git
synced 2024-09-19 21:03:23 +12:00
feat: Add option to store all tokens when they're created. (#91)
This commit is contained in:
parent
719826d66d
commit
f1cd72407a
12 changed files with 240 additions and 53 deletions
|
@ -1,24 +1,80 @@
|
|||
spark_locals_without_parens = [
|
||||
access_token_attribute_name: 1,
|
||||
access_token_expires_at_attribute_name: 1,
|
||||
api: 1,
|
||||
auth_method: 1,
|
||||
authorization_params: 1,
|
||||
authorize_path: 1,
|
||||
client_id: 1,
|
||||
client_secret: 1,
|
||||
confirm_action_name: 1,
|
||||
confirm_on_create?: 1,
|
||||
confirm_on_update?: 1,
|
||||
confirmation: 1,
|
||||
confirmation: 2,
|
||||
confirmation_required?: 1,
|
||||
confirmed_at_field: 1,
|
||||
destroy_action_name: 1,
|
||||
enabled?: 1,
|
||||
expunge_expired_action_name: 1,
|
||||
expunge_interval: 1,
|
||||
get_by_subject_action_name: 1,
|
||||
get_changes_action_name: 1,
|
||||
hash_provider: 1,
|
||||
hashed_password_field: 1,
|
||||
identity_field: 1,
|
||||
identity_relationship_name: 1,
|
||||
identity_relationship_user_id_attribute: 1,
|
||||
identity_resource: 1,
|
||||
inhibit_updates?: 1,
|
||||
is_revoked_action_name: 1,
|
||||
monitor_fields: 1,
|
||||
oauth2: 1,
|
||||
oauth2: 2,
|
||||
password: 1,
|
||||
password: 2,
|
||||
password_confirmation_field: 1,
|
||||
password_field: 1,
|
||||
password_reset_action_name: 1,
|
||||
private_key: 1,
|
||||
read_action_name: 1,
|
||||
read_expired_action_name: 1,
|
||||
redirect_uri: 1,
|
||||
refresh_token_attribute_name: 1,
|
||||
register_action_name: 1,
|
||||
registration_enabled?: 1,
|
||||
request_password_reset_action_name: 1,
|
||||
resettable: 0,
|
||||
resettable: 1,
|
||||
revoke_token_action_name: 1,
|
||||
sender: 1,
|
||||
sign_in_action_name: 1,
|
||||
subject_name: 1
|
||||
signing_algorithm: 1,
|
||||
signing_secret: 1,
|
||||
site: 1,
|
||||
store_all_tokens?: 1,
|
||||
store_changes_action_name: 1,
|
||||
strategy_attribute_name: 1,
|
||||
subject_name: 1,
|
||||
token_lifetime: 1,
|
||||
token_path: 1,
|
||||
token_resource: 1,
|
||||
uid_attribute_name: 1,
|
||||
upsert_action_name: 1,
|
||||
user_id_attribute_name: 1,
|
||||
user_path: 1,
|
||||
user_relationship_name: 1,
|
||||
user_resource: 1
|
||||
]
|
||||
|
||||
[
|
||||
import_deps: [:ash, :spark],
|
||||
import_deps: [:ash, :spark, :ash_json_api, :ash_graphql],
|
||||
inputs: [
|
||||
"*.{ex,exs}",
|
||||
"{dev,config,lib,test}/**/*.{ex,exs}"
|
||||
],
|
||||
plugins: [Spark.Formatter],
|
||||
locals_without_parens: spark_locals_without_parens,
|
||||
export: [
|
||||
locals_without_parens: spark_locals_without_parens
|
||||
]
|
||||
|
|
|
@ -19,7 +19,7 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
Attempt to confirm a user.
|
||||
"""
|
||||
@spec confirm(Confirmation.t(), map, keyword) :: {:ok, Resource.record()} | {:error, any}
|
||||
def confirm(strategy, params, options) do
|
||||
def confirm(strategy, params, opts \\ []) do
|
||||
with {:ok, api} <- Info.authentication_api(strategy.resource),
|
||||
{:ok, token} <- Map.fetch(params, "confirm"),
|
||||
{:ok, %{"sub" => subject}, _} <- Jwt.verify(token, strategy.resource),
|
||||
|
@ -27,7 +27,7 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
user
|
||||
|> Changeset.new()
|
||||
|> Changeset.for_update(strategy.confirm_action_name, params)
|
||||
|> api.update(options)
|
||||
|> api.update(opts)
|
||||
else
|
||||
:error -> {:error, InvalidToken.exception(type: :confirmation)}
|
||||
{:error, reason} -> {:error, reason}
|
||||
|
@ -37,8 +37,8 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
@doc """
|
||||
Store changes in the tokens resource for later re-use.
|
||||
"""
|
||||
@spec store_changes(Confirmation.t(), String.t(), Changeset.t()) :: :ok | {:error, any}
|
||||
def store_changes(strategy, token, changeset) do
|
||||
@spec store_changes(Confirmation.t(), String.t(), Changeset.t(), keyword) :: :ok | {:error, any}
|
||||
def store_changes(strategy, token, changeset, opts \\ []) do
|
||||
changes =
|
||||
strategy.monitor_fields
|
||||
|> Stream.filter(&Changeset.changing_attribute?(changeset, &1))
|
||||
|
@ -57,7 +57,7 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
extra_data: changes,
|
||||
purpose: to_string(strategy.name)
|
||||
})
|
||||
|> api.create() do
|
||||
|> api.create(Keyword.merge(opts, upsert?: true)) do
|
||||
:ok
|
||||
else
|
||||
{:error, reason} ->
|
||||
|
@ -74,8 +74,8 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
@doc """
|
||||
Get changes from the tokens resource for application.
|
||||
"""
|
||||
@spec get_changes(Confirmation.t(), String.t()) :: {:ok, map} | :error
|
||||
def get_changes(strategy, jti) do
|
||||
@spec get_changes(Confirmation.t(), String.t(), keyword) :: {:ok, map} | :error
|
||||
def get_changes(strategy, jti, opts \\ []) do
|
||||
with {:ok, token_resource} <- Info.authentication_tokens_token_resource(strategy.resource),
|
||||
{:ok, api} <- TokenResource.Info.token_api(token_resource),
|
||||
{:ok, get_changes_action} <-
|
||||
|
@ -85,7 +85,7 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
|> Query.new()
|
||||
|> Query.set_context(%{strategy: strategy})
|
||||
|> Query.for_read(get_changes_action, %{"jti" => jti})
|
||||
|> api.read() do
|
||||
|> api.read(opts) do
|
||||
changes =
|
||||
strategy.monitor_fields
|
||||
|> Stream.map(&to_string/1)
|
||||
|
|
|
@ -116,6 +116,17 @@ defmodule AshAuthentication.Dsl do
|
|||
""",
|
||||
default: false
|
||||
],
|
||||
store_all_tokens?: [
|
||||
type: :boolean,
|
||||
doc: """
|
||||
Store all tokens in the `token_resource`?
|
||||
|
||||
Some applications need to keep track of all tokens issued to
|
||||
any user. This is optional behaviour with `ash_authentication`
|
||||
in order to preserve as much performance as possible.
|
||||
""",
|
||||
default: false
|
||||
],
|
||||
signing_algorithm: [
|
||||
type: :string,
|
||||
doc: """
|
||||
|
|
|
@ -56,7 +56,7 @@ defmodule AshAuthentication.Jwt do
|
|||
"""
|
||||
|
||||
alias Ash.Resource
|
||||
alias AshAuthentication.{Info, Jwt.Config}
|
||||
alias AshAuthentication.{Info, Jwt.Config, TokenResource}
|
||||
|
||||
@typedoc """
|
||||
A string likely to contain a valid JWT.
|
||||
|
@ -104,12 +104,27 @@ defmodule AshAuthentication.Jwt do
|
|||
:error -> extra_claims
|
||||
end
|
||||
|
||||
case Joken.generate_and_sign(default_claims, extra_claims, signer) do
|
||||
{:ok, token, claims} -> {:ok, token, claims}
|
||||
with {:ok, token, claims} <- Joken.generate_and_sign(default_claims, extra_claims, signer),
|
||||
:ok <- maybe_store_token(token, resource) do
|
||||
{:ok, token, claims}
|
||||
else
|
||||
{:error, _reason} -> :error
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_store_token(token, resource) do
|
||||
if Info.authentication_tokens_store_all_tokens?(resource) do
|
||||
with {:ok, token_resource} <- Info.authentication_tokens_token_resource(resource) do
|
||||
TokenResource.Actions.store_token(token_resource, %{
|
||||
"token" => token,
|
||||
"purpose" => "generic"
|
||||
})
|
||||
end
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Given a token, read it's claims without validating.
|
||||
"""
|
||||
|
|
|
@ -38,6 +38,15 @@ defmodule AshAuthentication.TokenResource do
|
|||
How often to scan this resource for records which have expired, and thus can be removed.
|
||||
""",
|
||||
default: @default_expunge_interval_hrs
|
||||
],
|
||||
store_token_action_name: [
|
||||
type: :atom,
|
||||
doc: """
|
||||
The name of the action to use to store a token.
|
||||
|
||||
Used it `store_all_tokens?` is enabled in your authentication resource.
|
||||
""",
|
||||
default: :store_token
|
||||
]
|
||||
],
|
||||
sections: [
|
||||
|
|
|
@ -112,7 +112,35 @@ defmodule AshAuthentication.TokenResource.Actions do
|
|||
{:ok, revoke_token_action_name} <-
|
||||
Info.token_revocation_revoke_token_action_name(resource) do
|
||||
resource
|
||||
|> Changeset.for_create(revoke_token_action_name, %{"token" => token}, opts)
|
||||
|> 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
|
||||
|
|
27
lib/ash_authentication/token_resource/store_token_change.ex
Normal file
27
lib/ash_authentication/token_resource/store_token_change.ex
Normal file
|
@ -0,0 +1,27 @@
|
|||
defmodule AshAuthentication.TokenResource.StoreTokenChange do
|
||||
@moduledoc """
|
||||
Stores an arbitrary token.
|
||||
"""
|
||||
|
||||
use Ash.Resource.Change
|
||||
alias Ash.{Changeset, Error.Changes.InvalidArgument, Resource.Change}
|
||||
alias AshAuthentication.Jwt
|
||||
|
||||
@doc false
|
||||
@impl true
|
||||
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
|
||||
def change(changeset, _opts, _context) do
|
||||
with token when byte_size(token) > 0 <- Changeset.get_argument(changeset, :token),
|
||||
{:ok, %{"jti" => jti, "exp" => exp}} <- Jwt.peek(token),
|
||||
{:ok, expires_at} <- DateTime.from_unix(exp) do
|
||||
changeset
|
||||
|> Changeset.change_attributes(jti: jti, expires_at: expires_at)
|
||||
else
|
||||
_ ->
|
||||
changeset
|
||||
|> Changeset.add_error([
|
||||
InvalidArgument.exception(field: :token, message: "is not a valid token")
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -131,11 +131,51 @@ defmodule AshAuthentication.TokenResource.Transformer do
|
|||
validate_store_confirmation_changes_action(
|
||||
dsl_state,
|
||||
store_confirmation_changes_action_name
|
||||
) do
|
||||
),
|
||||
{:ok, store_token_action_name} <-
|
||||
Info.token_store_token_action_name(dsl_state),
|
||||
{:ok, dsl_state} <-
|
||||
maybe_build_action(
|
||||
dsl_state,
|
||||
store_token_action_name,
|
||||
&build_store_token_action(&1, store_token_action_name)
|
||||
),
|
||||
:ok <- validate_store_token_action(dsl_state, store_token_action_name) do
|
||||
{:ok, dsl_state}
|
||||
end
|
||||
end
|
||||
|
||||
defp validate_store_token_action(dsl_state, action_name) do
|
||||
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
|
||||
:ok <- validate_token_argument(action) do
|
||||
validate_action_has_change(action, TokenResource.StoreTokenChange)
|
||||
end
|
||||
end
|
||||
|
||||
defp build_store_token_action(_dsl_state, action_name) do
|
||||
arguments = [
|
||||
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :argument,
|
||||
name: :token,
|
||||
type: :string,
|
||||
allow_nil?: false,
|
||||
sensitive?: true
|
||||
)
|
||||
]
|
||||
|
||||
changes = [
|
||||
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :change,
|
||||
change: TokenResource.StoreTokenChange
|
||||
)
|
||||
]
|
||||
|
||||
Transformer.build_entity(Resource.Dsl, [:actions], :create,
|
||||
name: action_name,
|
||||
arguments: arguments,
|
||||
changes: changes,
|
||||
accept: [:extra_data, :purpose]
|
||||
)
|
||||
end
|
||||
|
||||
defp build_store_confirmation_changes_action(_dsl_state, action_name) do
|
||||
arguments = [
|
||||
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :argument,
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -133,7 +133,7 @@ defmodule AshAuthentication.MixProject do
|
|||
{:absinthe_plug, "~> 1.5", only: [:dev, :test]},
|
||||
{:ash_graphql, "~> 0.21", only: [:dev, :test]},
|
||||
{:ash_json_api, "~> 0.30", only: [:dev, :test]},
|
||||
{:ash_postgres, "~> 1.1", only: [:dev, :test]},
|
||||
{:ash_postgres, "~> 1.2.1", only: [:dev, :test]},
|
||||
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
|
||||
{:dialyxir, "~> 1.2", only: [:dev, :test], runtime: false},
|
||||
{:doctor, "~> 0.18", only: [:dev, :test]},
|
||||
|
|
2
mix.lock
2
mix.lock
|
@ -4,7 +4,7 @@
|
|||
"ash": {:hex, :ash, "2.4.24", "fb74aaf9ee8d9c8397c1c57d2d2ebf48cc0b3a933736eab66b25cea72826ac9f", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: true]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:spark, "~> 0.2.18", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.5.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e1b7ac0cf41af75f954bfb9500d1aeb54e4b3b34ec41dbe71c685b92ef8304ae"},
|
||||
"ash_graphql": {:hex, :ash_graphql, "0.22.2", "35f49776864e0d7abfd7cdded61d6b600e63792cad77cac24475c3606d2ea85e", [:mix], [{:absinthe, "~> 1.7", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:ash, "~> 2.4", [hex: :ash, repo: "hexpm", optional: false]}, {:dataloader, "~> 1.0", [hex: :dataloader, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fee44d457986587617d5ad11b262594a1ed689c81861f255dabbe628f1cde877"},
|
||||
"ash_json_api": {:hex, :ash_json_api, "0.30.1", "54e60c4862eee35ed8a9a925e5c99be2b80e36a2507355bdb0f0974defe82a8d", [:mix], [{:ash, "~> 2.0", [hex: :ash, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:json_xema, "~> 0.4.0", [hex: :json_xema, repo: "hexpm", optional: false]}, {:plug, "~> 1.11", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "b8b4827aa02de75a9a48d2941e813947da46b7dbfdd84cd20959dbaec103f830"},
|
||||
"ash_postgres": {:hex, :ash_postgres, "1.1.3", "d025ec75a0c64dccc58ff0fce7ec4a8a800f59aab1723c29dda28c2f9f068357", [:mix], [{:ash, "~> 2.1", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "59d92075052defe30744ee7eb721da3ffcb2cd8d8081766af2d6cd70619274a9"},
|
||||
"ash_postgres": {:hex, :ash_postgres, "1.2.1", "b4dfcda819e18e64c5d97bb23589e2d248f2fae303309aa766b46ebfdd655ae9", [:mix], [{:ash, ">= 2.4.0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "824441b3b01cada477a5a81d08aa4409b365bb447720132edde65679da2f6a2b"},
|
||||
"assent": {:hex, :assent, "0.2.1", "46ad0ed92b72330f38c60bc03c528e8408475dc386f48d4ecd18833cfa581b9f", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: true]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "58c558b6029ffa287e15b38c8e07cd99f0b24e4846c52abad0c0a6225c4873bc"},
|
||||
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.0.1", "9be815469e6bfefec40fa74658ecbbe6897acfb57614df1416eeccd4903f602c", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "486bb95efb645d1efc6794c1ddd776a186a9a713abf06f45708a6ce324fb96cf"},
|
||||
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
|
||||
|
|
|
@ -100,7 +100,7 @@ defmodule AshAuthentication.AddOn.Confirmation.ActionsTest do
|
|||
},
|
||||
~w[jti expires_at purpose extra_data]a
|
||||
)
|
||||
|> Example.Repo.insert!()
|
||||
|> Example.Repo.insert!(on_conflict: :replace_all, conflict_target: :jti)
|
||||
|
||||
{:ok, changes} = Actions.get_changes(strategy, jti)
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ defmodule Example.User do
|
|||
}
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id, writable?: true)
|
||||
uuid_primary_key :id, writable?: true
|
||||
|
||||
attribute(:username, :ci_string, allow_nil?: false)
|
||||
attribute(:hashed_password, :string, allow_nil?: true, sensitive?: true, private?: true)
|
||||
attribute :username, :ci_string, allow_nil?: false
|
||||
attribute :hashed_password, :string, allow_nil?: true, sensitive?: true, private?: true
|
||||
|
||||
create_timestamp(:created_at)
|
||||
update_timestamp(:updated_at)
|
||||
create_timestamp :created_at
|
||||
update_timestamp :updated_at
|
||||
end
|
||||
|
||||
actions do
|
||||
|
@ -70,9 +70,9 @@ defmodule Example.User do
|
|||
type :user
|
||||
|
||||
queries do
|
||||
get(:get_user, :read)
|
||||
list(:list_users, :read)
|
||||
read_one(:current_user, :current_user)
|
||||
get :get_user, :read
|
||||
list :list_users, :read
|
||||
read_one :current_user, :current_user
|
||||
end
|
||||
|
||||
mutations do
|
||||
|
@ -84,67 +84,68 @@ defmodule Example.User do
|
|||
type "user"
|
||||
|
||||
routes do
|
||||
base("/users")
|
||||
get(:read)
|
||||
get(:current_user, route: "/me")
|
||||
index(:read)
|
||||
post(:register_with_password)
|
||||
base "/users"
|
||||
get :read
|
||||
get :current_user, route: "/me"
|
||||
index :read
|
||||
post :register_with_password
|
||||
end
|
||||
end
|
||||
|
||||
postgres do
|
||||
table("user")
|
||||
table "user"
|
||||
repo(Example.Repo)
|
||||
end
|
||||
|
||||
authentication do
|
||||
api(Example)
|
||||
api Example
|
||||
|
||||
tokens do
|
||||
enabled?(true)
|
||||
token_resource(Example.Token)
|
||||
signing_secret(&get_config/2)
|
||||
enabled? true
|
||||
store_all_tokens? true
|
||||
token_resource Example.Token
|
||||
signing_secret &get_config/2
|
||||
end
|
||||
|
||||
add_ons do
|
||||
confirmation :confirm do
|
||||
monitor_fields([:username])
|
||||
inhibit_updates?(true)
|
||||
monitor_fields [:username]
|
||||
inhibit_updates? true
|
||||
|
||||
sender(fn user, token ->
|
||||
sender fn user, token ->
|
||||
Logger.debug("Confirmation request for user #{user.username}, token #{inspect(token)}")
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategies do
|
||||
password :password do
|
||||
resettable do
|
||||
sender(fn user, token ->
|
||||
sender fn user, token ->
|
||||
Logger.debug(
|
||||
"Password reset request for user #{user.username}, token #{inspect(token)}"
|
||||
)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
oauth2 :oauth2 do
|
||||
client_id(&get_config/2)
|
||||
redirect_uri(&get_config/2)
|
||||
client_secret(&get_config/2)
|
||||
site(&get_config/2)
|
||||
authorize_path(&get_config/2)
|
||||
token_path(&get_config/2)
|
||||
user_path(&get_config/2)
|
||||
authorization_params(scope: "openid profile email")
|
||||
auth_method(:client_secret_post)
|
||||
identity_resource(Example.UserIdentity)
|
||||
client_id &get_config/2
|
||||
redirect_uri &get_config/2
|
||||
client_secret &get_config/2
|
||||
site &get_config/2
|
||||
authorize_path &get_config/2
|
||||
token_path &get_config/2
|
||||
user_path &get_config/2
|
||||
authorization_params scope: "openid profile email"
|
||||
auth_method :client_secret_post
|
||||
identity_resource Example.UserIdentity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
identities do
|
||||
identity(:username, [:username], eager_check_with: Example)
|
||||
identity :username, [:username], eager_check_with: Example
|
||||
end
|
||||
|
||||
def get_config(path, _resource) do
|
||||
|
|
Loading…
Reference in a new issue