User authentication in Phoenix?

Yeah, I also feel that a nice default authentification implementation would improve onboarding big time, but I doubt it needing to be part of phoenix itself. And the difference to routing/templating is, that there are existing go to projects handling that. Plug does have a router, Eex is part of Elixir. It would be a waist to not use them.

4 Likes

I know this is a beaten subject, and Iā€™ve been trying to avoid it in the hope that a ā€œstandardā€ package would emerge for Phoenix authentication, but I need to add authn/authz to a web application (not only an API) and I would like to know the current state of affairs. :slight_smile:

From the last messages on this thread it seems that ā€œcoherenceā€ is the most widely used module. Does anyone know if it provides the following features?

  • Login page
  • User registration page
  • Password recovery method
  • Decorator that redirects to login page if not authenticated, exposes user info otherwise
  • Decorator to protect an API endpoint
  • Permissions
  • OAuth2 provider support (this is a stretch, maybe Iā€™ll have to use Authable)

Thanks!

1 Like

Coherence for me, sadly, is entirely untenable as it only supplies an internal registration. It has no support for external directories, no support for oauth (they are talking of it, but nothing yet), and its methods of injecting its views are a little different than usual phoenixā€™y stuff. ^.^

I currently just use ueberauth as it handles all login types fine, but it does not have any views or back-end handling (including nothing like the features you listed), however those tend not to be hard to make, just needs a library (and Iā€™d still not opt for automatic login/registration page handling). I had been playing with an idea to wrap uberauth in a coherence-like thing that handles all styles via protocol dispatch (and a default case the user could depend on as well for a stock coherence-like style), but Iā€™d also like to do more traditionally phoenix style view handling in it instead of using a host of generators, or not do views at all (maybe just some callback functions for form generation or so). Maybe when I get some free time again later, but for now I am too busy. ^.^;

4 Likes

I saw a project that started recently named curator.

It imitates devise features and adds hooks for additional features like coherence.

Any opinions on it?

3 Likes

Login page - yes
User registration page - yes
Password recovery method - yes
Decorator that redirects to login page if not authenticated, exposes user info otherwise - yes
Decorator to protect an API endpoint - not out of the box
Permissions - No, by design. Authorization is a separate concern from Authentication IMHO
OAuth2 provider support (this is a stretch, maybe Iā€™ll have to use Authable) - not yet.

Let me know if you have any more questions about coherence.

2 Likes

@OvermindDL1 what do you mean by "its methods of injecting its view are little different that usual phoenix stuff? Would love the feedbackā€¦

Just things I spoke to you about the time that you started it, you have your reasons for that style, I just find it difficult to work with comparatively. :slight_smile:

A few things are an enforced user schema style, id/password only, the authorization aspect is very lacking (and at least in my projects those were some of the huge parts that needed to get done ā€˜rightā€™), etcā€¦ Plus the fact it injects code all around instead of being used more like a library, instead of being a part of the project you use it becomes a thing that you have to work inside of. This is probably quite normal for the Ruby crowd (which I am not), but it is very much not normal for the Functional crowd. :slight_smile:

Hum, are you working on an OAuth provider implementation for Coherence? Cool. :slight_smile:

Another question. I want to persist my sessions outside the current beam vm, since I will have more than one application instance running and a user can hit any one of them. From the documentation it seems I have to implement Coherence.DbStore, is there a schema for the ā€œSessionā€ model that is referred in the documentation?

Also, even though the protocol is called DbStore I can store them anywhere, right? I was thinking of using Phoenixā€™s own session store which can be cookie based for example.

@OvermindDL1 I would love to get more details on your suggestions to improve Coherence if your willing too. We could do that here, or open a new issue on the project.

Here are some of things I would like to understand more:

  • ā€œA few things are an enforced user schema style, id/password onlyā€. Do you mean supporting authorizing on several fields like ā€œEmail or usernameā€? I just had that requirement and had to customize the generated controller.
  • ā€œPlus the fact it injects code all around instead of being used more like a libraryā€. Can you give me more information here? Perhaps an example on how its done now and how you would prefer it be done.

On the authorization front, I have not yet found an Elixir solution that Iā€™m happy with. Iā€™ve taken a stab at this a couple of time, but have not completed anything Iā€™m happy with.

I have a pretty strong opinion that authorization is a separate concern from authentication and that is why I have not provided anything in Coherence. With that said, I do believe that authentication is very important and would really like to have a story for people that use Coherence.

Thanks for your feedback. I really appreciate it.

@edevil DbStore is just an empty protocol which you need to implement. So, you can do anything in it. The example here should give you enough details to implement something.

The DbStore is design so it only hits the database (uses the protocol) if a session cannot be found in the Agent. So it should perform pretty wellā€¦

Well for example, Iā€™ve built up a little thing (very much not a library, I probably should put it in one sometime thoughā€¦), I have an account schema, GUID keys, this is the base of all the users information.

From that I have an account_google as one example, it holds the information like tokens and so forth from a google OAuth request, its primary key is a foreign key to the account primary key, always a one-to-one match and the google one cannot exist without the account one. I have a variety of other ones like this for github, steam, facebook, as well as an account_local schema. The local one exists in only one of my systems so far (I do not even have any form of a local login for the other dozen little servers I have, oauth only for them) but it contains a login id, hashed password, and a bit of other data.

Needless to say, coherence is very much not usable for the majority of authentication purposes Iā€™ve ever experienced.

Now in my thing Iā€™ve built up, say, a password reset thing, simple plug in the ueberauth style, it just redirects to the proper place for a given login type (say google) or handles a local one (I confirm they are who they are based on some internal information to this company so Iā€™ve not needed email yet, but that style would not be hard either).

I can go in to a lot more information at some other time, but Iā€™m fairly busy at the moment, in a crunch period. ^.^

Lots and lots of examples, but the biggest one for me is the *very* specific view style it uses, basically logins via websocket, other sources, or even customizing and breaking up views in unique ways (I have a lot of little subviews all over that does not fit that style well), I have more about this in a lot more detail, but I am not in the mindset right now (my mind is in oh-god-too-much-sql mode right now, Iā€™m making SQL queries that are many many pages in length, blehgā€¦)

It should not necessarily have a way to do authorization, but it needs a way to let you populate your own authorizations, for example in my system I use a set of allow/deny permissions with arguments (stored as json in the database currently, eh), but in addition to those populated I get information from google and LDAP and other places to give them or deny them more permissions, so I have to get that information from the authentication layer as it can change on the fly from those systems.

Coherence could become something really really useful over time, but so far it does not meet even my minimal requirements, ignoring the advanced features that I need that Iā€™m not even sure how to shoehorn into its current design. ^.^;

1 Like

@smpallen99 To use the Session Plug I would need access to Plug.Conn, which I donā€™t seem to have with the DbStore protocol.

Why doesnā€™t the Coherence Session auth make use of the already existing Phoenix sessions? There are already several backends that it can use.

1 Like

I just pushed an update to the coherence phx-1.3 branch that has support for using the latest coherence with both legacy phoenix and the new phx project structures. The work is not done yet, but there should be enough functionality to get going.

This branch now supports, what I believe, is a good Gettext implementation that allows full localization of all Coherence messages using your appā€™s Gettext module.

4 Likes

Hi, Iā€™ve read the description of the Coherence auth project and there are seems all features which I need for my project, specifically:
password restore
email confirmation
password bruteforce protection
Iā€™d like to try it out. But if I get it correctly, Coherence comes with itā€™s own router with own views and templates. As my project is gonna be multilingual and I plan to take the approach similar to described in the article http://code.parent.co/practical-i18n-with-phoenix-and-elixir/ where each url if it is not localized (first chunk should replicate locale ie en, uk, es, fr etcā€¦) is redirected to the localized in accordance with browser settings and configured list of allowed languages and fallback to default language if they donā€™t match.
As the phoenix 1.2 is currently the stable version Iā€™m gonna be using this.

Most of the auth examples Iā€™ve stambled upon donā€™t have localization in mind.
So, the question is how well will the Coherence play with multilinqual site like that. I need register, login, restore password pages to have localized pages (with gettext) as well as confirmation emails etcā€¦ Is there an example how to do it, how many and what kind of tweaks should be done?

hello, talking about authentication with Phoenix/Elixirā€¦ there was a conference ā€œElixir Daze 2017ā€ and The talk by JoĆ£o Moura was about what we can do to manage well this subject.
He has to attract the attention to the differences between coherence, uberauth, pot, guard and keeper (library that he is developing to work as Multi Factor Authentication), and the usage of Json Web Tokens.

here is the video link: ElixirDaze 2017- Tackling Authentication with Phoenix by JoĆ£o Maura
and his github repo: keeper

If it can helpā€¦

1 Like

@igor I canā€™t see anything obvious why you should not be able to use Coherence with this approach. I would create a quick spike to to try it and flush out any potential issues.

Couple things to consider:

  • Make sure the Coherence plugs come after the localization plugs
  • Use the phx-1.3 branch in Coherence
  • Use the mix coherence.install task, not the mix coh.install task.

If you do run into trouble, push your spike project to github so I can easily reproduce your issue.

I have tested the phx-1.3 branch with phoenix-1.3.0-rc with projects made with mix phoenix.new. I have not tested it on pre phoenix-1.3.0 projects however.

@smpallen99 I wanted to say thanks for your quick answer, it was a big help. I got the coherence v-1.3 working nicely with the localization and phoenix-1.3, which I finally have choosen for the project. To make it work there were only router settings needed to be a little customized. In case someone can find it usefull I will leave the router code here. May be there is some not necessary stuff, for example Iā€™m not sure about this

  # Add this block
  scope "/" do
    pipe_through :protected
    coherence_routes :protected
    
  end

part. It is never touched because of the locale plug which redirects user before the route gets called. But compiler seems wonā€™t generate helper path functions without it.

In general, itā€™s important to pay attention to the order of scopes and their namespaces because coherence needs all itā€™s paths to be in scopes which are not namespaced and all protected paths to go after all public paths to work properly.

defmodule MyProject.Web.Router do
  use MyProject.Web, :router
  use Coherence.Router         # Add this

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug MyProject.Web.Plug.Locale, "en"    
    plug Coherence.Authentication.Session  # Add this
  end

  pipeline :protected do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug MyProject.Web.Plug.Locale, "en"    
    plug Coherence.Authentication.Session, protected: true  # Add this
  end

  pipeline :api do
    plug :accepts, ["json"]
  end  
  
  # Add this block
  scope "/" do
    pipe_through :browser
    coherence_routes()
    scope "/", MyProject.Web do
      get "/", PageController, :index
    end    
  end

  # Add this block
  scope "/:locale", as: :locale do
    pipe_through :browser
    coherence_routes()
    
    scope "/", MyProject.Web do
      get "/", PageController, :index      
    end    
  end

  # Add this block
  scope "/" do
    pipe_through :protected
    coherence_routes :protected        
  end
  
  # Add this block
  scope "/:locale", as: :locale do
    pipe_through :protected
    coherence_routes :protected
    
    scope "/", MyProject.Web do
    # Add protected routes below
    end    
  end    
end

For now I have another question - what is the easyest way to provide the complex form for the anonimous user to register and at the same time create some content on the site which will be published after user confirms his account. Does the coherence provide the simple api function to be used in my controller to get the user registered and the confirmation email sent?

This block provides the routes for a logged in user. You can review the source in Coherence.Router for more specifics.

Iā€™m not sure if you using your own controllers, or have generated the coherence controllers. You can view the coherence controllers. For example these two lines in the Session create action are responsible for logging in a user. they could be called from the Registration controller create action.

@smpallen99

Yeah, I see. But in my router locale plug comes to work first and redirects such paths to /:locale/ā€¦ paths. For localized protected paths I have

   scope "/:locale", as: :locale do
    pipe_through :protected
    coherence_routes :protected
    
    scope "/", MyProject.Web do
    # Add protected routes below
    end    
  end   

As for my second question about creating complex form for registering user and at the same time adding some content to my site, Iā€™ve looked into coherence source, as you told me, particularly into RegistrationController and found that to register new user and send him a confirmation email there are two functions used, changeset and send_confirmation, both located in Coherence.ControllerHelpers, which do exactly what I need, thank you one more time!

Since it hasnā€™t been mentioned yet, how would OpenID fit into an Elixir / Phoenix Framework picture ?

Thereā€™s https://github.com/mustafaturan/shield/tree/ui that can be used as an identity provider. This could act as a separate process within an umbrella app, thus segregating user management concerns from the appā€™s domain.

there is also an erlang implementation of OpenID relying party https://github.com/indigo-dc/oidcc, which could be used (not sure if itā€™d had to be ported though ; being still a newbie in Elixir) to delegate login to a third party identity provider.

I understand this post is generic without implementation detail. What are your thoughts in terms of maintainability and security ?