cgraham

cgraham

Feature Request: For Passwordless implementation in mix gen auth, make it a magic code and not a link

Please change passwordless login from a link to a 6-8 digit code a user can enter.

Gen Auth in the latest RC 1.8 of Phoenix defaults to passwordless magic links where you click a link in an eamil.

Problem with magic link logins: Mobile email apps (looking at you Gmail) now embed their own web browser in such a way that when you click on a link in the email, it will log you into the embedded browser but NOT the user’s browser. So once the user closes the embedded browser in say the Gmail app, your login goes away.

The solution: Most passwordless logins have shifted to using a code (6-8 digits). The user then copies the code from the email and pastes into the web browser.

Example of this: We wrote two versions of this at https://www.rivalsee.com (which is an AI SEO tracker written in Elixir/Liveview) and https://www.tellmel.ai (an AI biographer written in Elixir/Liveview :slight_smile:

In both cases we implemented our own magic login code on top of Phoenix 1.8’s passwordless magic link login.

The request is to have the magic code be the default as it is becoming the standard everywhere because of the mobile app browser problem.

Thanks!

Most Liked

jswanner

jswanner

It’s part of the “Web authentication API” (webauthn) and uses the PublicKeyCredential interface available in the browser. Those APIs can be used for various things and support a number of options, none of which are called “passkeys,” making it confusing if you are just getting started in trying to implement passkeys, residentKey is what you’ll actually see in code and the documentation will also refer to them as “discoverable keys.” How tou use those browser APIs also depends on how you want your authentication process to flow: do you want the device to potentially trigger the passkey UI before you know who they are (this is what is meant by discoverable), or do you want the user to first provide a username/email and then trigger the passkey UI once you know your system has their public key.

The gist is that passkeys are private/public key pairs generated on the user’s device (or in something like 1password) via the JavaScript API, the private key is used to sign a challenge (random bytes previously generated on the server) on the device and the public key is used to verify the signature on the server.

There are two flows: creating a passkey and authenticating with a passkey. In both flows the server first generates and stores the challenge, sends the challenge to the client, which is included in the webauthn API call. The result of the creation API includes public key which needs to be stored by the server for future authentication flows. The result of the authentication API includes a signature of the challenge which the server needs to verify using the previously stored public key.

I recently spiked adding passkeys to what’s generated by phx.gen.auth in Phoenix 1.8 RC: First pass as passkeys · jswanner/phx-passkey-spike@dd88cf9 · GitHub

Schultzer

Schultzer

Username/password are still king, if anything it should have been passkeys. :man_shrugging:

garrison

garrison

Even if you rotate the code on every attempt the probability of randomly guessing a 6-digit numeric code is 1 / 1,000,000, so it would take on average 1 million requests to compromise an account. If on the other hand you never rotate the code and brute-force every possible code in order, it would take on average 500,000 requests to compromise an account. In other words, rotating the code does not buy you much.

This is rate-limiting, yes, but I disagree that it’s “not that hard”. The problem is that with such low-entropy codes the rate-limits go from “defense in depth” to holding up the security of the entire account system. If there is any bug in your rate-limiter then any account is trivially brute-forced. So you have to be very careful, which was my point.

As an example, say you limit each account to 1 attempt per hour. Now say you have 1 million users. All someone has to do is try every user over the course of each hour and they will on average get into one account per hour! So you have to rate-limit globally as well.

If this feature is being proposed for Phoenix all of this has to be carefully considered. Phoenix does not have any rate-limiting solution, so something will have to be built or added. If you pull in a dependency for rate-limiting (Hammer is one) then that dependency is now holding up the security of the entire auth stack, and has to be carefully audited for bugs.

Alternatively you could user higher entropy codes at the cost of the user experience. For a framework like Phoenix which has to cater to everyone, that might be a better path to go down.

Where Next?

Popular in Proposals: Ideas Top

Gladear
Hello everyone! tldr; I propose to add a way for VerifiedRoutes to know if they’re used for get, post, etc to make them even more robust...
New
beepboop
(re-post of: Feature idea: measure and expose socket latency · Issue #1890 · phoenixframework/phoenix_live_view · GitHub) This is relate...
New
tubedude
Hey, Earlier i posted a question, but after some research I think a proposal is due. Working on a Phoenix Live View app, I needed clien...
New
mikesax
On a Rails/Turbo site, the first page is typically loaded using http GET and then sockets are used navigate and replace HTML content for ...
New
snofang
In a typical business development task, having a function in a context module which accepts attributes of map type and passes them to Ect...
New
Jskalc
Hi everyone! Recently I was thinking a lot about the way HEEX renders lists. People are generally surprised about huge payloads being sen...
New
marcandre
I notice that most events have bindings (e.g. phx-keyup) but not the input event. The input event is the preferred way to interact with ...
New
MUSTDOS
Hello all! assign(socket, :name, “Elixir”) Why can’t we have assign/stream take a group of atoms and maps/structs as a default to r...
New
hst337
iex> map = %{x: 1} iex> map.x 1 iex> map.x() 1 Why would anyone use the map.x() syntax for getting map value? I’d suggest depre...
New
sevensidedmarble
I have a very simple suggestion: the generated config/dev.exs file should read from PORT at compile time to set the endpoints port. If ...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

We're in Beta

About us Mission Statement