dwyl / auth

πŸšͺ πŸ” UX-focussed Turnkey Authentication Solution for Web Apps/APIs (Documented, Tested & Maintained)
https://authdemo.fly.dev
GNU General Public License v2.0
130 stars 9 forks source link

Tech Question: Do we even Need an `AUTH_API_KEY`? πŸ’­ πŸ€·β€β™‚οΈ #277

Open nelsonic opened 1 year ago

nelsonic commented 1 year ago

Continuing on from our discussion in: https://github.com/dwyl/auth/issues/268 and with the benefit of our knowledge from Flutter and JS-land ... Trying to think about auth from first principals ... How are we going to enable auth in our Flutter app with the least code possible and without the need for keeping "secrets" ... πŸ’­

Why do we have an AUTH_API_KEY in the first place?

We (I) created an AUTH_API_KEY because I thought that it was needed for identifying/verifying which App is using auth for authenticating the person. But when I think about it with my beginner's mind I'm forced to think "Why...?" πŸ€·β€β™‚οΈ

If someone is running a Phoenix App on localhost then we know they are in "Dev" mode, right? πŸ‘©β€πŸ’» So why do they need to have an AUTH_API_KEY to identify them? πŸ€” The AUTH_API_KEY doesn't provide the person using the app any additional security it's just an extra step for the Dev/Engineer to setup ...

Does auth need an API_KEY or can we just do domain-based verification? πŸ’­

Can we just create an "Allowed List" for urls that are allowed to use auth and reject any other URL? We currently require the URL to be defined for an app, e.g: https://auth.dwyl.com/apps/45

image

If we are doing a domain-based verification, then do we need an AUTH_API_KEY? πŸ’­ What real additional security is the AUTH_API_KEY giving us? Is it just perceived security because we've been trained to think that API Keys are the "right" way to do this? πŸ€”

How will an attacker exploit a system that only has domain-based verification?

Hypothetically, if we were to completely remove the AUTH_API_KEY, how would a malicious person ("attacker") attempt to use our auth system to get people to login with their Google/GitHub/etc account and steal their data? πŸ’­

If the attacker can intercept a request or create a fake page that looks like our App, and use our own auth endpoint to authenticate a person and then replay the successful JWT back to the App they can read the person's data ...

How can we do domain-based verification on a Distributed App?

If our Flutter App is web-based or deployed to the App/Play Store, will there be a "domain" for it? πŸ’­ And if there is no domain associated with the "Native" App, how do we verify it? πŸ€·β€β™‚οΈ Is there a unique string associated with the iOS or Android build that cannot be spoofed?

These are the questions that are on my mind right now as I'm thinking about auth in general and specifically gearing up to re-write auth from first principals to be an order of magnitude simpler.

Note: Please only comment if you understand the security implications of this question. πŸ™ i.e: you have done a bit of white/grey hat hacking and understand how "hackers" think about compromising systems. πŸ¦Έβ€β™€οΈ

nelsonic commented 1 year ago

Supabase has the concept of an anon key: https://supabase.com/docs/guides/database/api#api-url-and-keys anon-key-in-web-context

"an anon key, which is safe to be used in a browser context."

i.e. people are putting these keys in plaintext in their web apps ...

@LuchoTurtle's recent speed-run of the Supabase + Flutter tutorial:

supabase-flutter-demo#42-adding-main-function-and-constants image

hard-coded into the demo app: https://github.com/dwyl/supabase-flutter-demo/blob/01a2902fb7a0950cd8af370ea0c1eeaa91e7750d/lib/main.dart#L19-L23

https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InltbGx1YnB0b2p4eXloZXFoZmJnIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzQ4MzU2ODksImV4cCI6MTk5MDQxMTY4OX0.DwTBckKPG63bObcqK2il-xt0uiWQXfuAxWS596RTUfk

image

Note: There's an active thread about how to disable anon key in the Supabase discussions: https://github.com/supabase/supabase/discussions/4547 ⏳ This is not the place to "bash" Supabase ... they have built their system how they see fit. πŸ‘ Instead I want to understand how we can do "anonymous" access to auth without needing to have an anon key which IMO is an anti-pattern.

An anon key encourages people to put the key in-the-clear e.g. in front-end JS apps. That means it provides exactly zero security. 0️⃣ So what's the point of having it? πŸ€·β€β™‚οΈ

nelsonic commented 1 year ago

OK, I've thought about this a lot from both the security and usability perspectives. πŸ’­ Crucially, if we're building a Native App using Flutter, πŸ“± and there isn't a way to protect an API key in Flutter, see: https://github.com/dwyl/learn-flutter/issues/82 πŸ” So while we aren't going to completely remove the AUTH_API_KEY, we are going to re-think it as "non-secure". πŸ”“ i.e. we won't use it as a "key" but rather as an "identifier". πŸ”‘ -> πŸ‘€ The key [breaking] change we will be making to the AUTH_API_KEY is the format:

auth.domain.com/:person_id/:public_key

Before:

88SwQD4YweF8q7iAt1RPVjwqnztrEP9Lm4XWn/88SwQGcsdq4gUpR9D69DFAXyZep/authdemo.fly.dev

After:

authdemo.fly.dev/88SwQD4YweF8q7iAt1RPVjwqnztrEP9Lm4XWn/88SwQGcsdq4gUpR9D69DFAXyZep

The change is pretty basic; on the surface ... Instead of having the URL as the last part of the AUTH_API_KEY, it will be at the start of the AUTH_API_KEY. But rather than this being a boring key, it will also be a functional URL/endpoint. i.e. visiting: authdemo.fly.dev/88SwQD4YweF8q/88SwQGcsdq4g in a browser will show the info/stats for the client - provided you successfully authenticate.

As previously noted, this is a breaking change so we will need to release a V2 of auth_plug.

We're going to make it explicit in all our docs that the AUTH_API_KEY does not contain anything sensitive and can safely be embedded in a front-end/Native App. The only reason to continue using environment variables to specify the key is to be able to switch between auth instances e.g: from authdemo.fly.dev to auth.dwyl.com or auth.acme.co

I think this is as simple as we can make it. We're always going to need an auth instance URL so the App knows where to send people to authenticate.

So the next question is: should we rename our SingleEnvironmentVariableTM from AUTH_API_KEY to AUTH_URL for clarity/simplicity given that it will in fact be just a URL not an "API Key"...? πŸ’­

LuchoTurtle commented 1 year ago

I agree with the changes. However, even though this following question might be me missing something...

I wonder if, even though the AUTH_URL is an identifier and not a key, can't it be used to impersonate other people, since the AUTH_URL is accessible by anyone in the browser?

nelsonic commented 1 year ago

AUTH_URL will be restricted to the person that is allowed to see it. πŸ” I will attempt to clarify this shortly. 🀞

nelsonic commented 1 year ago

But yes, you're right. perhaps the the AUTH_API_KEY name will be clearer to people ... πŸ’­

If the AUTH_API_KEY is left in-the-clear, e.g. committed to GitHub by mistake, it could be used to authenticate by someone that isn't the owner. This is the same as leaking any other API Key by committing it to GitHub. The mitigation will be: a) Having an "Allowed List" for the URL that is allowed authenticate. i.e. only app.dwyl.com https://github.com/dwyl/auth/issues/281 b) Additional check on a new device, i.e: for people authenticating on a new phone/computer they will have to verify via 2nd factor auth. TBD