Django auth, admin, and passkeys

Mostly just trying to start a conversation about passkeys, to see how people are feeling.

Passkeys are picking up steam, and look really promising as a great way to avoid storing passwords at all. Django does a great job of keeping up with making sure the way we store passwords is done well by default, but not storing them at all would be better, and with passkeys seeming like they’re getting significant traction.

I’m working on implementing Passkeys into a project of mine, and the current state of the passkey support in third party libraries is still somewhat unpolished, though I’ve definitely been greatly helped by their existence. After a bit of fighting with how things clash between my project and the third party library I’m using (django-passkeys), I’ve been able to get passkey registration going, and that feels pretty good.

Now I’m thinking about where I want to use it, and the Django Admin immediately comes to mind. I am thinking to work on figuring out how to get the Django admin working with the passkeys the way I’ve started implementing them, but I’m also thinking about what barriers, beside volunteer time and general carefulness, might hinder adoption of passkeys in the default Django admin.

We tend to want to prove things in third-party packages first and that’s good even here, but I did want to see if folks have thoughts or gotchas that it would be worth considering as I’m wondering about whether this could be contributed to Django. Right now my thinking is to keep digging into it to understand it more, and that should help me get a bit better grasp on what it might take to bundle passkeys with Django.

4 Likes

Hello,

here is Mohamed ElKalioby, the main contributor for django-passkeys.
Thanks for the nice words.

I think if you set your ‘LOGIN_URL’ to be the same LOGIN_URL where you are allowing your users to login to the app. Django Admin will redirect to that page which will allow passkeys.

I just finished listening to Passkeys for a passwordless future with Anna Pobletts from 1Password (Changelog Interviews #544) |> Changelog

And was thinking about the Django ecosystem. I am glad there is a package out there already and if the industry keeps going that way then it probably would make sense in my mind to have something like this in the Django auth module

So Justin Mayer has a package that he demoed at DjangoCon Europe in Porto for this:

I know @MarkusH and @apollo13 were working with him to advance it, maybe with an eye to lining it up for core? — but I’m not sure what the state of play there is ATM.

(:construction_worker_man:: Refs #34896 (First-party passkey support in django.auth) – Django — wontfix pending community discussion.)

2 Likes

Hi, yes Justin, Markus and I worked a bit on getting a release out and cleaning up a thing or two. I’d be very much in favor of improving kagi to the point where we could move it to core as opposed to manually re-implementing everything. This would allow for quicker iteration and earlier testing of the feature. That said it needs someone with time and willingness to push forward.

1 Like

For those interested, arianvp over on GitHub has posted about a form-associated custom element (FACE), developed as an HTML-driven interface to webauthn that looks really nice to me.

With the recent news of a grant for Allauth, which he intends in part to implement webauthn and passkeys, is there still appetite for passkeys to be included in Django proper? I still think that it would be very much worthwhile, even if Allauth gets it done first, but I want to check my gut on that with the community.

If so, is bringing in a third party library acceptable? I know we’ve generally avoided it historically, but I also think that has somewhat softened recently. It should be acceptable for it to be a soft dependency.

The implementation I’m currently working on (it’s not quite ready to share yet) avoids adding any routes, and is declared in a hypermedia-prioritizing way, rather than using AJAX calls. Include a javascript file and use some prescribe HTML to hook it up; it feels like a decent using API to me.

I think there is likely to be a temptation to expand passkeys to a more generic interface in order to support a greater portion of webauthn to use as second-factor devices. And I’m currently feeling like that would be unwise, even as I understand that it makes some sense. I worry about the more generic names being a less intuitive API that ends up hiding the “passkeys” terminology, and would instead be using the generic names “webauthn” and “resident keys”, which unfortunately just don’t roll off the tongue.

As I get something worth sharing, what’s the thought on the next step? Is a DEP the most appropriate next step, or is that heavy handed?

Hi @ryanhiebert. I think there’s still reason to pursue this. Not everyone uses allauth by a long way, and having multiple options is healthy.

… is bringing in a third party library acceptable?

Grrr. Maybe. There’d have to be some discussion. I’d imagine passkeys as a credential model linking to your User model, so it could be optional app to add, perhaps… (If it’s just (cough) a JS file, maybe we could vendor it :thinking:)

…what’s the thought on the next step?

Get it up as a third party app, so folks can start trying it out.

2 Likes

My 2 cents is that passkeys want to be in Django proper. One of the tag lines is “reassuringly secure” and regarding auth, to me, username & password no longer meet that standard by default.

Adding passkeys would bring Django to the state of the art again. Also updating auth was agreed to be a priority in the recent roadmap session.

Tossing this out there as a simple proof-of-concept app that you can drop in for adding passkey auth to the Django admin (and your own site):

It’s by no means production-ready, but serves as a good example (I think!) of how simple a webauthn implementation can be. The only dependency (aside from Django, obviously) is cryptography, and the entire API surface area is 2 views and 2 javascript functions.

2 Likes

@dcwatson I love it. I’m going to dig a little more into the backend code, as that’s the part I’ve given less attention to. I had presumed that it would be wisest to use a library to implement webauthn, and that was the dependency I was referring to. If this is simple enough, then I’m fine with dropping it and using cryptography instead. It’s not yet a dependency of Django yet, but if not I think that would be easier to get approval for.

For the work that I’ve been doing, I’ve been able to avoid the additional AJAX URLs, and I really like it. I don’t think there’s a lot of people doing it with a POST form in the page just like with username/password, but I think it works really well, and I really like the idea of not needing to install additional paths in the URL conf to make it work.

I’d be interested in talking synchronously with you or others doing work with implementing passkeys, although I know scheduling is difficult and often understandably disfavored.

I’m @dcwatson on the Django Discord - feel free to ping me there!

I think having additional URLs is mostly a separate concern from using AJAX. You could overload a view to check request.POST parameters or request.is_ajax() (RIP), or split them into separate views either way. But for a reusable app (not in core), I like having separate URLs so the caller doesn’t need to change their views.

Also, if there is a clear choice of which third-party library “everyone” uses for webauthn, I’m all in favor of using it. This project was mostly a learning exercise for me, thus the DIY approach.

Dear Bro Mohammed.
How are you ?

I am Trying nowadays to implement Django passkeys and i have smale typeError :
KEY_ATTACHMENT = None | passkeys.Attachment.CROSS_PLATFORM | passkeys.Attachment.PLATFORM

Could you help ! Please !

BR
Khaled

Hello,

This sets the type of key attachment you like to use

None: is to allow all
passkeys.Attachment.CROSS_PLATFORM is allow only roaming devices like security keys
passkeys.Attachment.PLATFORM is to allow only devices linked to a platform like TouchID and Windows Hello.

Preferably start with None to allow all devices

Got it.

Thanks Bro :rose: