stryderjzw
I’m newer to Elixir/Phoenix in general, but decided to give Ash a go because I really like the philosophy. However, I’m running into trouble setting up Google Oauth with Ash Authentication.
Actually, I set up magic link first using Igniter, but then realized in production, I can’t send emails yet, so I added password authentication. (This seemed to break magic link
)
Now I’m trying to add Google, as I want to build a prototype to read emails. After following instructions, the Sign in with Google button shows up, but clicking it just returns me back to /sign-in page.
There are no errors in the console… and this is where I’m a bit stuck with the Ash philosophy. If I’m declaring everything, how do I trace the code to find out what’s wrong? Am I just guessing which attributes are missing?
Here is my User resource:
defmodule Playground.Accounts.User do
use Ash.Resource,
otp_app: :playground,
domain: Playground.Accounts,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshAuthentication],
data_layer: AshSqlite.DataLayer
authentication do
add_ons do
log_out_everywhere do
apply_on_password_change?(true)
end
confirmation :confirm_new_user do
monitor_fields [:email]
confirm_on_create? true
confirm_on_update? false
auto_confirm_actions [
:register_with_google,
:sign_in_with_magic_link,
:reset_password_with_token
]
sender Playground.Accounts.User.Senders.SendNewUserConfirmationEmail
end
end
tokens do
enabled? true
token_resource Playground.Accounts.Token
signing_secret Playground.Secrets
store_all_tokens? true
require_token_presence_for_authentication? true
end
strategies do
magic_link do
identity_field :email
registration_enabled? true
sender Playground.Accounts.User.Senders.SendMagicLinkEmail
end
password :password do
identity_field :email
resettable do
sender Playground.Accounts.User.Senders.SendPasswordResetEmail
# these configurations will be the default in a future release
password_reset_action_name :reset_password_with_token
request_password_reset_action_name :request_password_reset_token
end
end
google do
client_id Playground.Secrets
redirect_uri Playground.Secrets
client_secret Playground.Secrets
end
end
end
sqlite do
table "users"
repo Playground.Repo
end
actions do
defaults [:read]
read :get_by_subject do
description "Get a user by the subject claim in a JWT"
argument :subject, :string, allow_nil?: false
get? true
prepare AshAuthentication.Preparations.FilterBySubject
end
read :get_by_email do
description "Looks up a user by their email"
get? true
argument :email, :ci_string do
allow_nil? false
end
filter expr(email == ^arg(:email))
end
create :sign_in_with_magic_link do
description "Sign in or register a user with magic link."
argument :token, :string do
description "The token from the magic link that was sent to the user"
allow_nil? false
end
upsert? true
upsert_identity :unique_email
upsert_fields [:email, :confirmed_at]
# Uses the information from the token to create or sign in the user
change AshAuthentication.Strategy.MagicLink.SignInChange
metadata :token, :string do
allow_nil? false
end
end
action :request_magic_link do
argument :email, :ci_string do
allow_nil? false
end
run AshAuthentication.Strategy.MagicLink.Request
end
update :change_password do
# Use this action to allow users to change their password by providing
# their current password and a new password.
require_atomic? false
accept []
argument :current_password, :string, sensitive?: true, allow_nil?: false
argument :password, :string, sensitive?: true, allow_nil?: false
argument :password_confirmation, :string, sensitive?: true, allow_nil?: false
validate confirm(:password, :password_confirmation)
validate {AshAuthentication.Strategy.Password.PasswordValidation,
strategy_name: :password, password_argument: :current_password}
change {AshAuthentication.Strategy.Password.HashPasswordChange, strategy_name: :password}
end
read :sign_in_with_password do
description "Attempt to sign in using a email and password."
get? true
argument :email, :ci_string do
description "The email to use for retrieving the user."
allow_nil? false
end
argument :password, :string do
description "The password to check for the matching user."
allow_nil? false
sensitive? true
end
# validates the provided email and password and generates a token
prepare AshAuthentication.Strategy.Password.SignInPreparation
metadata :token, :string do
description "A JWT that can be used to authenticate the user."
allow_nil? false
end
end
read :sign_in_with_token do
# In the generated sign in components, we validate the
# email and password directly in the LiveView
# and generate a short-lived token that can be used to sign in over
# a standard controller action, exchanging it for a standard token.
# This action performs that exchange. If you do not use the generated
# liveviews, you may remove this action, and set
# `sign_in_tokens_enabled? false` in the password strategy.
description "Attempt to sign in using a short-lived sign in token."
get? true
argument :token, :string do
description "The short-lived sign in token."
allow_nil? false
sensitive? true
end
# validates the provided sign in token and generates a token
prepare AshAuthentication.Strategy.Password.SignInWithTokenPreparation
metadata :token, :string do
description "A JWT that can be used to authenticate the user."
allow_nil? false
end
end
create :register_with_password do
description "Register a new user with a email and password."
argument :email, :ci_string do
allow_nil? false
end
argument :password, :string do
description "The proposed password for the user, in plain text."
allow_nil? false
constraints min_length: 8
sensitive? true
end
argument :password_confirmation, :string do
description "The proposed password for the user (again), in plain text."
allow_nil? false
sensitive? true
end
# Sets the email from the argument
change set_attribute(:email, arg(:email))
# Hashes the provided password
change AshAuthentication.Strategy.Password.HashPasswordChange
# Generates an authentication token for the user
change AshAuthentication.GenerateTokenChange
# validates that the password matches the confirmation
validate AshAuthentication.Strategy.Password.PasswordConfirmationValidation
metadata :token, :string do
description "A JWT that can be used to authenticate the user."
allow_nil? false
end
end
action :request_password_reset_token do
description "Send password reset instructions to a user if they exist."
argument :email, :ci_string do
allow_nil? false
end
# creates a reset token and invokes the relevant senders
run {AshAuthentication.Strategy.Password.RequestPasswordReset, action: :get_by_email}
end
update :reset_password_with_token do
argument :reset_token, :string do
allow_nil? false
sensitive? true
end
argument :password, :string do
description "The proposed password for the user, in plain text."
allow_nil? false
constraints min_length: 8
sensitive? true
end
argument :password_confirmation, :string do
description "The proposed password for the user (again), in plain text."
allow_nil? false
sensitive? true
end
# validates the provided reset token
validate AshAuthentication.Strategy.Password.ResetTokenValidation
# validates that the password matches the confirmation
validate AshAuthentication.Strategy.Password.PasswordConfirmationValidation
# Hashes the provided password
change AshAuthentication.Strategy.Password.HashPasswordChange
# Generates an authentication token for the user
change AshAuthentication.GenerateTokenChange
end
create :register_with_google do
argument :user_info, :map, allow_nil?: false
argument :oauth_tokens, :map, allow_nil?: false
upsert? true
upsert_identity :unique_email
change AshAuthentication.GenerateTokenChange
# Required if you have the `identity_resource` configuration enabled.
change AshAuthentication.Strategy.OAuth2.IdentityChange
change fn changeset, _ ->
user_info = Ash.Changeset.get_argument(changeset, :user_info)
Ash.Changeset.change_attributes(changeset, Map.take(user_info, ["email"]))
end
# Required if you're using the password & confirmation strategies
upsert_fields []
change set_attribute(:confirmed_at, &DateTime.utc_now/0)
change after_action(fn _changeset, user, _context ->
case user.confirmed_at do
nil -> {:error, "Unconfirmed user exists already"}
_ -> {:ok, user}
end
end)
end
end
policies do
bypass AshAuthentication.Checks.AshAuthenticationInteraction do
authorize_if always()
end
policy always() do
forbid_if always()
end
end
attributes do
uuid_primary_key :id
attribute :email, :ci_string do
allow_nil? false
public? true
end
attribute :hashed_password, :string do
allow_nil? true
sensitive? true
end
end
identities do
identity :unique_email, [:email]
end
end
Much appreciate any insights.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
sevenseacat
The first step would be looking at your Phoenix server logs - what’s happening when you click sign in? Is it redirecting somewhere and then redirecting back to your app?
The second part would probably be to turn on debugging for authentication failures in development - see AshAuthentication.Debug — ash_authentication v4.14.1 for details.
As to magic link being broken, we’d probably need some more information about how exactly it’s broken before we can start to diagnose how to fix it!
stryderjzw
Ah, the debug would be very helpful! Thank you for that.
There’s a lot of documentation for Ash and it can be a bit overwhelming, but I’m getting there.
stryderjzw
Looks like the Magic Link issue is only when trying to log in to accounts that aren’t confirmed. Getting the following error:
I found the Confirmation Tutorial. I’m guessing this is the issue, although the error is a bit cryptic.
Will try one of the ways to handle magic link confirmation after lunch!
zachdaniel
This definitely looks like a bug. Please open a bug showing that stack trace on
ash_sqlitestryderjzw
Done!
https://github.com/ash-project/ash_sqlite/issues/134
stryderjzw
Alright, going back to debugging Google Signin…
Turned on debugging for authentication failures, but no errors.
Looks like it just hits the /auth/user/google route and redirects back to the sign in page.
Not sure if this is how it’s supposed to show up, but the button is grey compared to the other signin buttons.
zachdaniel
Alright, so that first issue you mentioned should be fixed, will be released next week.
Could I see how your router is set up? Are you getting into your
AuthControllerat all? i.e in thefailurecallback?stryderjzw
You guys are amazing! Thank you.
My router.ex:
Here’s the log:
I’m… not sure if it goes into AuthController. It looks like it hits the /auth/user/google route and just redirects.
Here’s my mix phx.routes:
zachdaniel
The first thing to do would be to drop some
dbgorIO.inspectcalls in theAuthControllersuccess and failure callbacks to see if its getting there, and if its getting into the failure callback to see what the error isstryderjzw
Will do. Thanks for being patient with a new Elixir developer.