Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More clarity on how this app should be used for to provide authentication for a startup business using Elixir/Phoenix #149

Open
tadasajon opened this issue Oct 8, 2021 · 8 comments
Labels
question A question needs to be answered before progress can be made on this issue starter A beginner-friendly issue that is a good starting point for a new person technical A technical issue that requires understanding of the code, infrastructure or dependencies

Comments

@tadasajon
Copy link

I'm building a phoenix app and I'm interested in a user login system. I will need to connect with my users' Google.com accounts and Telegram.org accounts, so I need something that gives me a bit more power that phx.gen.auth (which I also don't like because it clutters up my codebase).

It is taking me a long time to understand how I would use this package to provide authentication for my app, however -- this is not a library that I can add to my app's mix.exs file, for instance.

What I have gathered so far is that I will need to run two phoenix apps: my own app that I am interested in providing authentication for, and also this app, which will have to be deployed at another domain, perhaps auth.tadasajon.com if my app is running at tadasajon.com.

What I will then have is essentially an OAuth login system that I will use from my own phoenix app, and that potentially other websites can use as well if they would like their users to be able to login with their tadasajon.com accounts for some reason.

The way my Tadasajon.com app will use this app is through the auth_plug library, which I will add to my mix.exs file in my Tadasajon app.

Do I understand this correctly so far?

Also, I noticed that this codebase is under the GNU General Public License v2.0 -- I am not building free software, however. I'm just building a website that people are going to log in to and then pay me money so my partner and I can make a million dollars. It is not my intention to distribute the software I am building or to make it open source -- I only intend to provide a service to users who want to buy widgets. So I just want to be sure that this licensing does not require me to forsake making any money and also does not require all the code that I write to be open source.

Thanks!

@nelsonic nelsonic added question A question needs to be answered before progress can be made on this issue starter A beginner-friendly issue that is a good starting point for a new person technical A technical issue that requires understanding of the code, infrastructure or dependencies labels Oct 8, 2021
@nelsonic
Copy link
Member

nelsonic commented Oct 8, 2021

Hi @tadasajon 👋
Stoked you found the repo(s). 🎉
Thanks for opening this issue to clarify understanding. 💭
It's a sign we haven't done a particularly good job of explaining things. 🙄

A bit of back-story: we have built several client (consulting) Phoenix Apps that include bespoke authentication systems. It's a painful waste-of-time to keep re-building the same (or similar) auth systems each time. So we decided to abstract it. Initially we thought the auth app could be an umbrella app and simply included as a git submodule to keep the main app uncluttered with auth code. But we soon realised that using an umbrella app was still going to have coupled code. So we instead decided to make auth a completely independent app that we could run on a subdomain.

Your understanding of how to use auth and auth_plug are correct.
If you were to run the auth app on a subdomain e.g. auth.tadasajon.com
then you would simply configure auth_plug in your main tadasajon.com app to point to that.

As for the GPL license, it's the same one used for Linux and Wordpress https://wordpress.org/about/license/
anyone is free to use it for commercial purposes. That's probably one of the biggest advantages of having auth on a subdomain your closed-source million-dollar-idea business logic can be completely separate.
I'm not a lawyer so don't quote me on any of this, but this is my understanding of reading the GPL.
This is a good FAQ: https://www.gnu.org/licenses/gpl-faq.en.html and this might answer your questions:
https://softwareengineering.stackexchange.com/questions/47032/can-i-use-gpl-software-in-a-commercial-app

Hope that helps.

@tadasajon
Copy link
Author

I've asked this question on ElixirForum.com https://elixirforum.com/t/solving-auth-once-and-for-all-does-this-proposed-solution-make-sense/44143 -- I'm interested in identifying my blindspots and misunderstandings.

@nelsonic
Copy link
Member

Hi @tadasajon, I don't think you're going to get particularly positive feedback on Elixir Forum on what we have built here. Especially now that mix phx.gen.auth #133 has been added to the Phoenix "core". It will be seen as the "standard" way of doing auth.

I guarantee you that people will find faults with what we have implemented here.

Especially people who have never had to manage multiple (client) apps and therefore won't have felt the pain of updating those Apps which may all have slightly different implementations/naming/etc. 🙄

I wish people with strong opinions on Auth would open issues (the way you have) so that we can discuss & improve.

As stated above, for our use case, we prefer to have separation of concerns so that our business logic can be as simple as possible. This is essentially a basic (Open Source) implementation of an "Auth-as-a-Service" product like Auth0.

Note: I'm not suggesting that what we have built is anywhere near as feature-rich as Auth0,
they have 900 employees and way more features (complexity) than any one organisation could ever need.

If you read the Auth0 feature list they have Role-Based-Access-Control (RBAC) + Permission: https://auth0.com/docs/authorization/rbac/manage-permissions
Some people might consider RBAC to be "scope creep", but it's really not; it's highly relevant related feature.
The moment your "building" has more than one door and you want to control who has access to what, RBAC is immediately useful/essential.

A good example of why having auth separate from our main App is a good idea (for us) is our recent implementation of the logout functionality. #159 The App using auth_plug only needs to call one function AuthPlug.logout/1 and everything is handled transparently dwyl/auth_plug_example#16 (review)
If you had to implement this (with tests) in an app using phx.gen.auth you would add hundreds of lines of code to your codebase, code you would have to maintain.

Multitenancy ?

For the uninitiated, read the Wikipedia summary: https://en.wikipedia.org/wiki/Multitenancy#Complexity

We have built/worked on multitenanted Apps several times before.
When that functionality is needed, multitenancy can make sense, but in general it adds a lot of complexity.
Our approach is far more pragmatic and offers most of the benefits with far lower cognitive overhead.
I'd call what we have multientancy "light" i.e. the benefits without carbs.

In an Auth instance the Apps <--> People relationship is essentially "many-to-many".
A person can login to one or more App without the other apps knowing about it.

When a person first logs-in to auth a person record is created and the (original) app_id is stored.
Additionally for each time they authenticate for any App a session #159 record is created.
They can then login to any app using auth and their session will record the app_id for that session.
i.e. a person can be logged into multiple Apps on multiple devices and have many concurrent sessions.
Their roles/permissions are also distinct/separate for each App.

In fact, now that we have sessions, we could easily refactor our codebase to remove the person.app_id.
That way the person record is totally independent from apps and thus "many-to-many". The sessions table would act as the "lookup" that joins the two.

The only thing we're not currently doing is distinct passwords/passphrases per App, that's beyond our use case.
See: "Passwords are Obsolete": https://medium.com/javascript-scene/passwords-are-obsolete-how-to-secure-your-app-and-protect-your-users-1cd6c7b7c3bc
We have email + password based registration/authentication as a convenience for people who don't have a Google Account (or don't want to use their Google Account to authenticate), but from our experience when Google OAuth is available, most people automatically use it.

Having one email + password combo per App could easily be achieved if that usecase was indeed required.

With a service like Fly.io running an instance of the auth App will cost $2/month because of their Free Tier.
We will be deploying one soon. We've been testing it with dwyl/hits#128 and dwyl/hits#133 so far our Hits App is costing us $1/month on Fly.io because the VMs are all in the Free tier. We're only paying for the SSD space to store the data.

@tadasajon
Copy link
Author

@nelsonic thanks for the extremely useful insight you added. I'm going to try to get your auth app running again. I'm kind of surprised that this isn't the default way that doing auth is understood since it seems like the slightly higher price in complexity upfront will pay off hundreds of times over.

@tadasajon
Copy link
Author

@nelsonic I'd be curious what you think about taking an approach like Firebase or Supabase for authentication.

https://firebase.google.com/docs/auth

https://supabase.com/docs/guides/auth

@nelsonic
Copy link
Member

nelsonic commented Dec 3, 2021

@tadasajon I cannot resist answering questions. They help me to think critically about how I build things. So thanks! 🙌

Very good follow-up questions. ❓
The answer to your question is 3 questions:

  1. How much do you want to trust a 3rd party to manage the personal data of the people using your App(s)? 🔐
  2. How much time do you have to setup and understand how everything works? ⌛
  3. What happens if something goes wrong and you are locked out of your own system? 🤦‍♂️

Supabase 🦸

We're delighted that Supabase exists and they are tackling the "Open Source Firebase" challenge. 🎉
They are using PostgreSQL and Elixir

We've been following them since their initial announcement last year on HackerNews:
https://news.ycombinator.com/item?id=23319901 > dwyl/how-to-choose-a-database#14
but it's very much still in "Alpha" ...

image

What do I do with an error like this? 🤷‍♂️ https://app.supabase.io/ ... where do I even start to debug it?
image

I know some people using it in production, but they are building an NFT exchange and like to live dangerously! 😜
I certainly wouldn't use it yet ... Not because they aren't building something awesome, just because I don't have time to debug when it breaks. I fully intend to explore it later when the need arises.

The fairly major "red flag" 🚩 that has stopped me form experimenting with Supabase is their lack of testing.

If you read through the /tests directory you will find a ghost town ... 👻

image

The integration tests are 64 lines of TypeScript code:
https://github.com/supabase/supabase/blob/master/tests/integration/index.test.ts
image

You can skim through the tests in 2 mins and make up your mind how reliable you think it will be. 💭
Whenever I see a lack of focus on testing I know the project is not for me. (yet...!)
More in the intro to this tutorial: https://github.com/dwyl/learn-tdd
There is really zero excuse for a stack to not be comprehensively tested.
They have focussed on adding features at breakneck speed at the expense of testing them for reliability.

Firebase 🔥

As for Firebase it's a good product that locks you tightly into the Google Cloud ecosystem.
If you're comfortable with that, go for it! Don't waste your time with Elixir or Phoenix and just use Flutter! 🦋

We've read some horror stories on HN of people having their GCP account locked/blocked and being locked out for days until they were able to leverage Twitter/HN to get their account unblocked ... GCP is not run by Humans, it's AI! 🤖

Please, don't take my word for this, read these posts that have thousands of "votes" from devs:

Make up your own mind how much you want to trust your company/app to Google.
If you're already using GCP and are happy with it. Then Firebase Auth is a logical choice.
Again, there are plenty of companies using GCP/Firebase for their apps and not having issues.
e.g:

The mega companies that spend millions a month on GCP and feature in the "success stories",
have dedicated teams of humans (account managers and support engineers) to handle their requests.

A small startup has to deal with GCP's automated support system. i.e. /dev/null

image

Again, any system is good when it works reliably.
The question you've always got to ask is: what happens when it goes wrong?

tl;dr > pick the Auth system that meets your needs. 🔍

FWIW: we really didn't want to build an Auth system ... 🙄
We would much prefer to save the time and use something someone else made & tested. ⏳
We spent hundreds of hours reading code in several programming languages to figure out if there was already something out there that we could use that was Open Source, reliable, well-tested/documented & maintainable. Didn't find it. 😞

Our goal with this project is something very different from what others are building.
We aren't focussing on adding more features, rather we are optimising for "Project Startup Time" and "Developer Happiness", i.e. the speed with which a new member of the team can get up-to-speed with running the project using Auth.
Having a single environment variable to run an app that uses auth_plug
that someone can get in 1 minute "self-serve" is what we want long-term.

Our plan is akin the Japanese family-companies that have 100 Year business plans: https://www.bbc.com/worklife/article/20200211-why-are-so-many-old-companies-in-japan
It's very much a long-term mindset.

The way that influences our decisions is simple: we don't use any tech that we cannot run ourselves independently.
We could run our entire stack disconnected from the internet on a Raspberry Pi powered by a solar panel + battery if we needed to ... 🏡
We use a handful of things for convenience like AWS SES for sending email, but we aren't "locked in" and since we have experience running our own mail servers and if we ever need to we could switch in a few hours.

Let us know what you decide. 👍
As always, we're here to help if you get stuck. 👩‍💻

@tadasajon
Copy link
Author

@nelsonic thanks for a thoughtful response. I guess we're still undecided on how we're going to handle auth. It seems like we may be able to use Firebase auth from an otherwise Phoenix/Elixir ecosystem. Supabase seems like it may be too much of a moving target for us.

It seems clear to me that once one has begun thinking in terms of managing two phoenix apps that both need to do user authentication and authorization, then one may as well be thinking in terms of managing fifty such apps.

So it should be possible for someone to set up a Phoenix app with auth-as-a-service that provides user authentication and role-based authorization for all the other Phoenix apps that they may create.

It seems to me that this auth library, if combined with rbac, fields elixir-auth-google, elixir-auth-github, auth_plug, and maybe a couple of others, could be used to build and deploy a functioning auth-as-a-service system running on Fly.io.

Then anyone who wanted to deploy a Phoenix app on Fly.io infrastructure and needed to think about user login could just clone this project and run the deploy scripts with the appropriate account credentials.

I guess since this is open source work there is nothing to stop me from trying to pull these projects together into a package that can be easily deployed on Fly, so maybe that's what I'll start fiddling with.

@tadasajon
Copy link
Author

I'd be curious to compare your offering to KeyCloak, as well. KeyCloak seems to be a fairly widely used java implementation of what you've tried to build in this auth package. https://www.keycloak.org

I'm writing my main apps in Phoenix, but does that mean I should also use an auth system written in Elixir? Isn't all the interaction between them going to be over OAuth protocols that are agnostic as to the underlying tech stacks?

I can't stand working in Java, and KeyCloak is written in Java, but it seems to me that I'd mainly be administering an underlying application, not really working directly in Java. So it seems like the real concerns should be how easy it is to administer the app.

I suppose if I used this auth app I'd feel more comfortable diving into the source code and following all the reasoning.

My main concern is that the entire area of authentication is rather sensitive and it's a good idea to get it correct and not have security holes or other problems down the road. If, by chance, the purpose for which I'm building all this takes off, and I'm managing millions of users accounts and working at a multi-million dollar production scale, then how well will the underlying auth package and deployment system hold up? And will I be able to get out of pickles?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question A question needs to be answered before progress can be made on this issue starter A beginner-friendly issue that is a good starting point for a new person technical A technical issue that requires understanding of the code, infrastructure or dependencies
Projects
None yet
Development

No branches or pull requests

2 participants