riverrun / phauxth Goto Github PK
View Code? Open in Web Editor NEWNot actively maintained - Authentication library for Phoenix, and other Plug-based, web applications
Not actively maintained - Authentication library for Phoenix, and other Plug-based, web applications
Hey @riverrun
Just wondering how the 1.5 branch is coming along? Is it breaking? Just looking to implement Phauxth in a greenfield project and I'm pretty new with Elixir & Phoenix so I'm trying to make sure I am working with stable packages.
Cheers,
Rich
Replace term_to_binary and binary_to_term variants with JSON encoding / decoding (provided by Poison).
Tokens created with the old implementation will no longer be valid after upgrading Phauxth to the new, JSON, implementation.
Hi @riverrun, and thanks again for the Phauxth library, it really "just works".
I noted when testing user controller actions, you create a session to test the actions that need a logged-in user. Regarding this, the authors in Programming Phoenix say:
You might be tempted to place the user_id in the session for the Auth plug to pick up:
conn()
|> fetch_session()
|> put_session(:user_id, user.id)
|> get("/videos")This approach is a little messy. We don’t want to store anything directly in the session, because we don’t want to leak implementation details.
The way they do it is they just put a user in conn.assigns and add a condition to the auth plug to first check if there is already a user in conn.assigns. The auth plug is tested in isolation.
I don't know if your familiar with this, but I would like to know the reason behind the decision to do that this way. ( I must say, however, I honestly don't know what they mean with "we don't want to leak implementation details").
Email messages should be internationaized
There doesn't seem to be a built-in solution for resending confirmation emails? Sometimes the email might be lost or end up in spam etc.
I have tried:
pipeline :api do
plug :accepts, ["json"]
plug :fetch_session
plug Phauxth.Authenticate, method: [:token, :session], user_context: Beta.Users
end
But failed with:
no function clause matching in Phauxth.Authenticate.get_user/2
(phauxth) lib/phauxth/authenticate.ex:35: Phauxth.Authenticate.get_user(%Plug.Conn{adapter:
I'm just guessing, but it seems Phauxth.Token.verify isn't compatible with receiving a socket instead of a connection. The error I am getting is:
Request: GET /socket/websocket?token=fake_token&vsn=2.0.0
** (exit) an exception was raised:
** (ArgumentError) argument error
:erlang.apply(%Phoenix.Socket{assigns: %{}, channel: nil, channel_pid: nil, endpoint: Test.Endpoint, handler: Test.UserSocket, id: nil, join_ref: nil, joined: false, private: %{}, pubsub_server: Reddlst.PubSub, ref: nil, serializer: Phoenix.Transports.V2.WebSocketSerializer, topic: nil, transport: Phoenix.Transports.WebSocket, transport_name: :websocket, transport_pid: #PID<0.6284.0>, vsn: "2.0.0"}, :config, [])
(phauxth) lib/phauxth/token.ex:74: Phauxth.Token.get_key_base/1
What do you think about adding support for socket to Phauxth.Token. Phoenix.Token has done it
https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/token.ex
I think perhaps it's a namespacing issue? Library looks really promising, thanks for the hard work and effort 👍
Request: POST /sessions
** (exit) an exception was raised:
** (UndefinedFunctionError) function Bcrypt.no_user_verify/1 is undefined (module Bcrypt is not available)
Bcrypt.no_user_verify([])
(phauxth) lib/phauxth/login.ex:38: Phauxth.Login.check_pass/4
(phauxth) lib/phauxth/login.ex:38: Phauxth.Login.verify/3
Invalidating active phoenix sessions in case any do get compromised does require changing the session secret, a.k.a. dropping all active sessions. A more secure way would be to add some kind of db backed session key to the session, which can be reset/changed independently per user.
Some of this could already be changed with phauxth by using custom implementations, but it seems the assumption of the session holding a current_user
key with the user_id
is hardcoded into the project.
Is this something you would consider adding? I might even send a PR, because otherwise your library seems really nice.
See here:
https://youtu.be/w3lKmFsmlvQ?t=24m9s
https://elixirforum.com/t/33-elixirconf-2017-plugging-the-security-holes-in-your-phoenix-application/8565/21
I'm trying to migrate some projects from Phx1.2/Openmaize to Phx1.3/Phauxth, so I've start to play with Phauxth 0.15, but it seems that v.015 isn't yet ready when the --confirm
option is given, because eight tests failed with these two kinds of errors:
** (UndefinedFunctionError) function Phauxth.Confirm.gen_token/0 is undefined or private
and
** (UndefinedFunctionError) function Phauxth.Confirm.verify/2 is undefined or private. Did you mean one of: * verify/3
I've created a new playground project through the following steps:
new project:
$ mix phx.new alibaba_html_confirm && cd alibaba_html_confirm
phauxth setup (html + confirm):
$ mix phauxth.new --confirm
add following dependency to mix.ex file:
{:phauxth, "~> 0.15"}, {:bcrypt_elixir, "~> 0.12"}
run usual initialization commands:
$ mix deps.get && mix deps.compile && mix ecto.create && mix ecto.migrate
run tests:
$ mix test
Full transcript of the errors:
[alibaba_html_confirm]$ mix test
...
...
.......10:51:35.793 request_id=glv3c4k25r1t1j8ejak36qp7k3ldjkv2 [warn] user=nil message="invalid password"
..10:51:37.130 request_id=rcf15o9v97ip75oq6s1trs5f9kjphi6o [warn] user=nil message="account unconfirmed"
..........
test confirmation fails for incorrect key (AlibabaHtmlConfirmWeb.ConfirmControllerTest)
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:21
** (UndefinedFunctionError) function Phauxth.Confirm.verify/2 is undefined or private. Did you mean one of:
* verify/3
code: conn = get(conn, confirm_path(conn, :new, email: email, key: key))
stacktrace:
(phauxth) Phauxth.Confirm.verify(%{"email" => "[email protected]", "key" => "pu9-VNdgE8V9QzO19RLCG3KUNjpxuixg"}, AlibabaHtmlConfirm.Accounts)
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:8: AlibabaHtmlConfirmWeb.ConfirmController.new/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:24: (test)
test confirmation fails for incorrect email (AlibabaHtmlConfirmWeb.ConfirmControllerTest)
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:29
** (UndefinedFunctionError) function Phauxth.Confirm.verify/2 is undefined or private. Did you mean one of:
* verify/3
code: conn = get(conn, confirm_path(conn, :new, email: email, key: key))
stacktrace:
(phauxth) Phauxth.Confirm.verify(%{"email" => "[email protected]", "key" => "pu9-VNdgE8V9qZo19rlcg3KUNjpxuixg"}, AlibabaHtmlConfirm.Accounts)
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:8: AlibabaHtmlConfirmWeb.ConfirmController.new/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:32: (test)
test confirmation succeeds for correct key (AlibabaHtmlConfirmWeb.ConfirmControllerTest)
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:13
** (UndefinedFunctionError) function Phauxth.Confirm.verify/2 is undefined or private. Did you mean one of:
* verify/3
code: conn = get(conn, confirm_path(conn, :new, email: email, key: key))
stacktrace:
(phauxth) Phauxth.Confirm.verify(%{"email" => "[email protected]", "key" => "pu9-VNdgE8V9qZo19rlcg3KUNjpxuixg"}, AlibabaHtmlConfirm.Accounts)
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:8: AlibabaHtmlConfirmWeb.ConfirmController.new/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/confirm_controller.ex:1: AlibabaHtmlConfirmWeb.ConfirmController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/confirm_controller_test.exs:16: (test)
test reset password fails for invalid email (AlibabaHtmlConfirmWeb.PasswordResetControllerTest)
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:25
** (UndefinedFunctionError) function Phauxth.Confirm.gen_token/0 is undefined or private
code: conn = post(conn, password_reset_path(conn, :create), password_reset: @invalid_email)
stacktrace:
(phauxth) Phauxth.Confirm.gen_token()
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:11: AlibabaHtmlConfirmWeb.PasswordResetController.create/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:26: (test)
test reset password fails for incorrect key (AlibabaHtmlConfirmWeb.PasswordResetControllerTest)
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:30
** (UndefinedFunctionError) function Phauxth.Confirm.PassReset.verify/2 is undefined or private. Did you mean one of:
* verify/3
code: conn = put(conn, password_reset_path(conn, :update), password_reset: @invalid_attrs)
stacktrace:
(phauxth) Phauxth.Confirm.PassReset.verify(%{"email" => "[email protected]", "key" => "pu9-VNDGe8v9QzO19RLCg3KUNjpxuixg", "password" => "^hEsdg*F899"}, AlibabaHtmlConfirm.Accounts)
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:27: AlibabaHtmlConfirmWeb.PasswordResetController.update/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:31: (test)
test reset password succeeds for correct key (AlibabaHtmlConfirmWeb.PasswordResetControllerTest)
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:19
** (UndefinedFunctionError) function Phauxth.Confirm.PassReset.verify/2 is undefined or private. Did you mean one of:
* verify/3
code: conn = put(conn, password_reset_path(conn, :update), password_reset: @valid_attrs)
stacktrace:
(phauxth) Phauxth.Confirm.PassReset.verify(%{"email" => "[email protected]", "key" => "pu9-VNdgE8V9qZo19rlcg3KUNjpxuixg", "password" => "^hEsdg*F899"}, AlibabaHtmlConfirm.Accounts)
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:27: AlibabaHtmlConfirmWeb.PasswordResetController.update/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.action/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/controllers/password_reset_controller.ex:1: AlibabaHtmlConfirmWeb.PasswordResetController.phoenix_controller_pipeline/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.plug_builder_call/2
(alibaba_html_confirm) lib/alibaba_html_confirm_web/endpoint.ex:1: AlibabaHtmlConfirmWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/alibaba_html_confirm_web/controllers/password_reset_controller_test.exs:20: (test)
.
Finished in 13.8 seconds
34 tests, 8 failures
Randomized with seed 268880
[alibaba_html_confirm]$
Is there a way to allow verify (login) when confirmed_at is nil? I scaffolded with confirm on, but I don't want to require it for login.
There is an Phauxth.Otp plug which provides a one-time password check. However, there is currently no guidance on how to integrate this into a web application. Considering that many security issues arise from implementation errors, there needs to be more information about implementation in the wiki and / or documentation.
I guess my issue could be split into multiple parts:
authentication.ex
instead?how can we setup new project for both api and browser support
Params contain 'user_id' as my user_id, and 'id' refers to a nested resource in the project I'm working with.
This means I can't use the id_check plug effectively. I'm wondering if there's some way around it. I'm a novice to Phoenix in general, so I'm sure I must be doing something a bit wacky.
The routes look something like this -- http://localhost:4000/users/2/route_details/5
The '2' in this case is (obviously) a user's ID and the '5' is the particular 'route_details' I'm trying to access or delete. My params in this case would look like %{"user_id" => "2", "id" => "5"}
I'm mostly just having issues with deleting things, as the :delete action is one of the things I had going through the :id_check plug. I was tempted to just write a :user_id_check plug, but it seems that this might be considered an issue anyway, so I thought you might be interested to know.
Hopefully this makes some sense. My project isn't very complex -- it's mostly the boilerplate stuff.
I want user able to keep track of where they have logged (remember me) and ability to manually sign out (e.g., lost device).
I'm thinking of adding a :cookies field just like sessions, so user can choose to remove unwanted cookie.
In Phauxth.Remember:
def call(%Plug.Conn{req_cookies: %{"remember_me" => token}} = conn, {opts, log_meta}) do
case get_user(conn, token, opts)
|> report(log_meta)
|> set_user(conn)
do
%Plug.Conn{assigns: %{current_user: nil}} ->
delete_rem_cookie(conn)
_ ->
conn
end
end
def get_user(conn, token, {max_age, user_context, opts}) do
with {:ok, user_id} <- Token.verify(conn, token, max_age, opts)
%{cookies: cookies} = user <- user_context.get(user_id),
true <- Map.has_key?(cookies, token),
do
user
end
end
field :cookies, :map
cookies: %{
"SFMyNTY.eyJzaWduZWQiOjE1MzYwODY4OTEsImRhdGEiOjF9.E8Gk7Gv2mqcLQMh8uyZdXie58fjHU7yu2jHozBFOu5Q" => %{
"timestamp" => System.system_time(:second),
"user-agent" => "Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53",
"remote_ip" => {127, 0, 0, 1}
}
}
I think better to store it in a separate table.
I assume that the default setting of 4 hours max-age for token validity does not take into consideration if the token is actively being used or if it is idle, i.e. it always expires 4 hours after generation (login). How to make it expire only after 4 hours of being idle (not used)?
I am trying to verify the token inside:
def connect(%{"token" => token}, socket) do
IO.puts token
case Phoenix.Token.verify(socket, "user salt", token, max_age: 86400) do
{:ok, user_id} ->
IO.puts user_id
socket = assign(socket, :user, Repo.get!(User, user_id))
{:ok, socket}
{:error, _} ->
IO.puts "error"
:error
end
end
But getting errors. How to use Phauxth.Token.verify
instead of Phoenix.Token.verify
to verify the Phauxth
token in this context (channels and sockets)?
Hi,
Love the project and I'm considering ripping out a similar implementation in a project at work for phxauth as it's more complete.
One thing on our design document is some additional session metadata so we can display something akin to https://github.com/blog/1658-view-active-browser-sessions;
If I put together a patch, would this be something you'd be interested in pulling in? Currently I'm thinking of morphing the sessions field into an embeds_many
Given a list of roles, I am trying to check if one of the roles is contained in the roles set. Can the wiki include an example?
user.ex schema
schema "users" do
...
field :role, {:array, :string}
...
end
user_controller.ex
plug :role_check, [roles: ["admin", "superadmin"]] when action in [:index, :delete]
authorize.ex
def role_check(%Plug.Conn{assigns: %{current_user: nil}} = conn, _opts) do
auth_error conn, "You need to log in to view this page", session_path(conn, :new)
end
def role_check(%Plug.Conn{assigns: %{current_user: current_user}} = conn, opts) do
if opts[:roles] && current_user.role in opts[:roles], do: conn,
else: auth_error conn, "You are not authorized to view this page", user_path(conn, :index)
end
Just made a new project and grabbed 0.10 for a simple demo, getting the following error on running the migrations for the first time:
== Compilation error on file lib/sesh2/web/controllers/confirm_controller.ex ==
** (UndefinedFunctionError) function Phauxth.Confirm.init/1 is undefined or private
Phauxth.Confirm.init([])
(plug) lib/plug/builder.ex:193: Plug.Builder.init_module_plug/3
(plug) lib/plug/builder.ex:181: anonymous fn/4 in Plug.Builder.compile/3
(elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3
(plug) lib/plug/builder.ex:181: Plug.Builder.compile/3
(phoenix) expanding macro: Phoenix.Controller.Pipeline.__before_compile__/1
lib/sesh2/web/controllers/confirm_controller.ex:1: Sesh2.Web.ConfirmController (module)
(elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in
Kernel.ParallelCompiler.spawn_compilers/1
This is a very basic setup, just followed the guides on the wiki. Steps to recreate:
mix phx.new sesh2
mix phauxth.new --confirm --api
vim mix.exs #add dependency
vim router.ex #add routes
mix ecto.setup
EDIT: So I had a chance to actually sit down and look, and there are no init
or call
functions in Phauxth.Confirm. I'm guessing this is expected? Should we be whipping up our own version of these depending on what method (email/sms) we want to use?
I have an umbrella application with my business logic in an app named AppExample
, and my web application in an app named AppExampleWeb
. This means that my user_context
is App.Accounts
, instead of AppWeb.Accounts
, the default that Phauxth
uses. This is fixable by overwriting the user_context
config for Phauxth
, but Phoenix actually already has a configuration field that specifies what application your contexts live in, for the purpose of using generators:
config :app_example_web,
generators: [context_app: :app_example]
Instead of defaulting the user_context
to the current application, you could instead see whether the generators are configured in such a manner.
Bamboo is now at 1.0, update Phauxth's dependency to match.
I tried to install v0.10 and the installer didn't work. I am getting errors like:
[error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type "Atom" not found
somepath/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
I'd also like to take the chance to thank you for your great work on comeonin, openmaize, phauxth and other projects.
This is my favorite Authentication solution I've found by far. @riverrun can you set up some kind of way for people to donate to this project? I 'd like to see it succeed and if getting you paid some helps that then I'm in.
Hi.
Thanks for phauxth..
Where can I find && alter this message: Invalid credentials
Cant find it..
Greetings
This is more of a Phoenix question, but I want both kinds of auth in my app (token for API access, session for the website). Is the correct way to have two SessionController
modules?
I've started using this and, firstly, just want to say it's a very nice library. I have one question though: I would've expected that the Authenticate
plug would return a 401 status when a current_user wasn't found. Is there a way to easily extend the plug to do this? Or do I just need to write another plug function to check if current_user
is nil?
Thanks again for the library!
Hi David.
I get a 500 when I submit the passwort_forgotten form without filling in an email..anything I can do?
See phoenixframework/phoenix@928cc6a and phoenixframework/phoenix#2530
When I tried mix phauxth.new
, code such as user_path
are generated in views, while it should really be Routes.user_path
now, after this change in Phoenix.
I'm not sure if this is already addressed in version 2.0 of phauxth
. A quick search doesn't seem to find any related issue, so I opened this.
By that I mean it overwrites a bunch of files, which makes it a bit harder to use on an existing project. Instead it would be sweet if it acted like the new phx.gen.context mix task that only appends to the file instead of overwriting.
This may or may not be hard, I'm not sure how to best go about this. Either some sort of string manipulation, but the best would be to actually parse the code, modify the AST, and render it back again. Perhaps one could use macros to great effect here. Or look at how the various code formatters/linters do it.
Anyway, I do love it though. After a bit of manual restoration (while still keeping the important changes) it works very nice.
The current behavior of phauxth
installer is to provide either:
api
switch is used.It would be nice to have additional switch for the installer to specify a JSON API setup based on session / cookie storage (not tokens) since storing the token inside a session cookie provided best security (compared to storing it for example in local storage by the client side JS application).
You are welcome to join the discussion here:
Sending cookies for stateless SPA authentication using JWT
phauxth/installer/new/templates/user_controller.ex
Lines 42 to 45 in 44e8f28
Regardless of the url (/users/1
, /users/2
,…) it always shows the current_user
(same for the other actions). Not exactly what I would expect.
Is the stage too early for my expectations?
This change is outlined in #69.
When calling the Plugs and verify functions, it should be easy to add custom metadata to the Phauxth.Log output.
meta
second argument to each of the Report functions.log_meta
option to the verify functions.
log_meta
option to Authenticate / Remember Plugs.Hello,
First of all, thank you for working on phauxth, I'm really enjoying using it !
The library still has some hardcoded (english) strings in some places, like in https://github.com/riverrun/phauxth/blob/master/lib/phauxth/confirm/report.ex .
While this is not an issue for logs, some of theses messages appears for the end-user, so it needs to be translated in some way.
A nice developper experience would be to allow the library user to translate those string from its app .po files, like any other string. Being able to use the gettext mix tasks like mix gettext.extract
would be a plus.
I could help with this, but I'm not sure how you'd want to approach this.
The Coherence library, for exemple, does this by implementing a Messages behavior (https://github.com/smpallen99/coherence/blob/bcff8bc6276596496e66da3376c8a8da2fe4c185/lib/coherence/messages.ex) that's implemented from the user app side (https://github.com/smpallen99/coherence/blob/bcff8bc6276596496e66da3376c8a8da2fe4c185/priv/templates/coh.install/coherence_messages.ex).
Sorry if this is a silly question but I couldn't find any other way to ask it, and there was no information in the wiki.
Do I understand it right that:
When you initially enter invalid user credentials, it redirects you back to /sessions/new. Immediately after, you enter in valid user credentials, you are then redirected to /sessions and receive a no route error.
Steps to reproduce:
/sessions/new
Invalid credentials
error message/sessions
and receive a no route found for GET /sessions
errorThanks for developing Phauxth. I've added the library incrementally to my project; I started by running mix phauxth.new
a while back, and today manually pulled in code generated by the --confirm
flag.
While testing password resets I kept receiving the error message "user already confirmed" which was confusing. After digging I realized I was matching into line 27 of Phauxth.Confirm.Report:
def report(%{} = user, _, meta) do
Log.warn(%Log{user: user.id, message: "user already confirmed", meta: meta})
{:error, Config.user_messages().already_confirmed()}
end
because my users table did not have the reset_sent_at
column.
I'm guessing others may also upgrade incrementally in the future. Although I recognize I didn't follow the recommended installation method, it would have helped debugging if the pattern matching in Phauxth.Confirm.Report was more specific and an exception occurred -- happy to submit a small PR if you think this would be a good addition
Hi David,
I understand you're pretty busy these days, and just wanted to check with you if 2.0 can be used in production? I know it has a lot of changes under the hood, but just wanted to double check before I use it in any client projects :)
It would be a good idea to have either a default user that is created upon installation or a mix task to create such a user.
Right now I had to comment out the plug Phauxth.Authenticate
in the router.ex to bypass the authentication so that I can create an account the very first time.
I can't seem get the Login to work with pbkdf2. It is still finding the Bcrypt reference somewhere even though I never added it.
mix phauxth.new
Mix.exs
defp deps do
[
{:phoenix, "> 1.3.0"},> 1.0"},
{:phoenix_pubsub, "
{:phoenix_ecto, "> 3.2"},> 2.10"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "
{:phoenix_live_reload, "> 1.0", only: :dev},> 0.11"},
{:gettext, "
{:phauxth, "> 1.2"},> 0.12"},
{:pbkdf2_elixir, "
{:bamboo, "> 0.8"},> 1.0"}
{:cowboy, "
]
end
user.ex
defp put_pass_hash(%Ecto.Changeset{valid?: true, changes:
%{password: password}} = changeset) do
change(changeset, Comeonin.Pbkdf2.add_hash(password))
end
session_controller.ex
def create(conn, %{"session" => params}) do
case Login.verify(params, Accounts) do
{:ok, user} ->
session_id = Login.gen_session_id("F")
Accounts.add_session(user, session_id, System.system_time(:second))
Phauxth.Login.verify(params, Alibaba.Accounts, crypto: Comeonin.Pbkdf2)
Login.add_session(conn, session_id, user.id)
|> login_success(user_path(conn, :index))
{:error, message} ->
error(conn, message, session_path(conn, :new))
end
end
Request: POST /sessions
** (exit) an exception was raised:
** (UndefinedFunctionError) function Comeonin.Bcrypt.check_pass/3 is undefined (module Comeonin.Bcrypt is not available)
Comeonin.Bcrypt.check_pass(%Alibaba.Accounts.User{meta: #Ecto.Schema.Metadata<:loaded, "users">, email: "[email protected]", id: 3, inserted_at: ~N[2018-02-23 14:09:14.155021], password: nil, password_hash: "$pbkdf2-sha512$160000$lsXaMTkXhwirR.TXArvc4Q$Mrl8FKhXh7kMRdhbZB/B99BQ9c05p9q3bxgwf7HW6cdQDYkqhYBwBCyBdebMpaCMCmVmrbxvmULIjI1Apj6n3Q", sessions: %{}, updated_at: ~N[2018-02-23 14:09:14.157897]}, "password", [])
(phauxth) lib/phauxth/login.ex:8: Phauxth.Login.verify/3
(alibaba) lib/alibaba_web/controllers/session_controller.ex:18: AlibabaWeb.SessionController.create/2
(alibaba) lib/alibaba_web/controllers/session_controller.ex:1: AlibabaWeb.SessionController.action/2
(alibaba) lib/alibaba_web/controllers/session_controller.ex:1: AlibabaWeb.SessionController.phoenix_controller_pipeline/2
(alibaba) lib/alibaba_web/endpoint.ex:1: AlibabaWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.call/1
(alibaba) lib/alibaba_web/endpoint.ex:1: AlibabaWeb.Endpoint.plug_builder_call/2
(alibaba) lib/plug/debugger.ex:99: AlibabaWeb.Endpoint."call (overridable 3)"/2
(alibaba) lib/alibaba_web/endpoint.ex:1: AlibabaWeb.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /home/dankmeme/elixir/alibaba/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
17:23:40.751 [error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type 'Atom' not found
17:23:40.759 [error] Loading of ~/.mix/archives/phauxth_new/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
17:23:40.772 [error] Loading of ~/.mix/archives/phauxth_new/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
17:23:40.772 [error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type 'Atom' not found
17:23:41.070 [error] Loading of ~/.mix/archives/phauxth_new/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
17:23:41.071 [error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type 'Atom' not found
Generated project app
17:23:41.585 [error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type 'Atom' not found
17:23:41.589 [error] Loading of ~/.mix/archives/phauxth_new/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
17:23:41.868 [error] Loading of ~/.mix/archives/phauxth_new/phauxth_new/ebin/Elixir.Mix.Tasks.Phauxth.New.beam failed: :badfile
17:23:41.868 [error] beam/beam_load.c(1287): Error loading module 'Elixir.Mix.Tasks.Phauxth.New':
mandatory chunk of type 'Atom' not found```
This is on macOS X sierra, not sure that it makes any difference. Had tried to setup openmaize on phoenix 1.3 then realised you'd created this to cover the new phoenix.
I noticed that the success
flash message is missing after a successful password change. I believe this is due to the configure_session(conn, drop: true)
on line: https://github.com/riverrun/phauxth/blob/master/installer/new/templates/password_reset_controller.ex#L45
Is this because drop: true
causes the response to drop the Phoenix flash messages? I did some testing with IEx.pry
, and the flash message is still in the conn
when the controller action exits. So, perhaps this is happening after.
In any case, I was able to get the flash message to show up by adding the renew: true
option to configure_session/2
(https://hexdocs.pm/plug/1.4.3/Plug.Conn.html#configure_session/2). This apparently "generates a new session id for the cookie." So, I'm not sure this is what everyone wants. But, I am using it to get the message to show.
If this is something you'd like a PR for, I'd be happy to assist.
Hi David,
I would like to use Phauxth in an advanced project that will have both html (for web users) and api (for Rest client App) authentication, and I'm wondering which is the best workflow/approach for setting up the Phauxth stuff.
Ideally, the umbrella project should have this kind of structure:
my_umbrella
|__ apps
|__ core
|__ core_web
|__ phauxth
|__ phauxth_api_web
|__ phauxth_html_web
where core
and core_web
will contains the app specific stuff, phauxth
will contain the shared Phauxth Ecto Context, phauxth_api_web
contains the rest api authentication server, and phauxth_html_web
contains the html frontend app server for accounts administration.
I think that having two separated Phauxth app for html and api it should be easier to mantain than having a single hybrid app.
I would like to be able to use the Phoauxth installer to set up the Context, Api and Html CRUD and Tests stuff rather than doing it by hand, doing something similar to:
$ mix new my_umbrella --umbrella && cd my_umbrella/apps
$ mix phx.new.ecto core
$ mix phx.new.web core_web
$ mix phx.new.ecto phauxth
$ mix phx.new.web phauxth_api_web --no-html --no-brunch
$ mix phx.new.web phauxth_html_web
$ cd phauxth && mix phauxth.new --ecto --confirm
$ cd phauxth_api_web && mix phauxth.new --api --confirm --context phauxth
$ cd phauxth_html_web && mix phauxth.new --html --confirm --context phauxth
But currently, the Phoauxth installer cannot be used neither for setting up an hybrid html+api app (as it hasn't a switch for specifying a desidered namespace) nor for setting up an umbrella app (if used with an umbrella app seems that it mess up its files).
Do you think that a) in a future the installer will support a sort of --namespace foo
switch for namespacing the generated files, and b) that there will be a support for umbrella projects?
In the mean time, can you give us some hints for which can be the best workflow to setting up Phauxth things with the current version of the installer in an umbrella project in general and in particular like the one above?
phauxth/installer/new/templates/accounts_test.exs
Lines 69 to 70 in 21b10fb
The key generated in that test doesn't seem to have any actual usage.
The add_rem_cookie function should accept plug's 'extra' option, one might want to add additional headers to their rem cookies, i.e. "SameSite=Lax".
I'm looking at how I can add custom login logic as shown by the Phauxth.Confirm.Login.
I've implemented my own custom login module which pulls in the base via use Phauxth.Login.Base
defmodule Beffect.Accounts.Login do
use Phauxth.Login.Base
alias Beffect.Accounts.User
# This is the custom logic path I'm running into problems with.
def check_pass(%User{active: false}, _, _, _) do
{:error, "account locked"}
end
# this custom logic works fine because the report method to handle that is already defined via
# https://github.com/riverrun/phauxth/blob/a61a2f3ac2d9a9334de571561dc0371af2484b8c/lib/phauxth/login/base.ex#L130
def check_pass(%User{invite_confirmed_at: nil}, _, _, _) do
{:error, "account unconfirmed"}
end
def check_pass(user, password, crypto, opts) do
super(user, password, crypto, opts)
end
end
The problem I'm running into is that if I want to output a custom message for my active: false
path I run into the problem that I can't easily define the report handler function like the ones already in the Phauxth.Login.Base
ones.
IE: If I try to add a report method like this to my Beffect.Accounts.Login
I get an conflict compile time error.
defmodule Beffect.Accounts.Login do
....
alias Phauxth.Log
def report({:error, "account locked"}, _, meta) do
Log.warn(%Log{message: "account locked", meta: meta})
{:error, "Account Locked!"}
end
...
end
Produces:
(CompileError) lib/beffect/accounts/login.ex:33: imported Phauxth.Login.Base.report/3 conflicts with local function
My question is:
1: where should I be defining the custom report/3
functions.
2: is there a way we can decouple the Phauxth.Login.Base methods from custom logic paths like Confirm. Not sure having the report methods there is the best place for them.
I ran the installer with an existing app (mix phauxth.new --confirm --remember) and whether I prompted "y" or "n" when asking if I wanted to overwrite files, I couldn't find any backup files.
Thank you for Phauxth.
I have noticed that authentication works for subsequent requests (after login) by sending authorization
header and user_id
as parameter.
Is it possible, taken also security considerations into account, to authenticate subsequent requests with authorization token only?
If user_id
must be submitted with every subsequent request, how to obtain it from the server? On successful login, the user gets access_token
only. Is it safe to return the user_id
with that response also?
Thank you.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.