Handle provisioning from existing membership system

I had an idea, based on work with an existing organization with a membership system with OIDC-based authentication. My idea is that they could build DID and handle provisioning into their existing system. Basically, from the user’s side, they would select a username foo, the organisation would have a domain name, say example.social, and then, at a click of a button, they would get @foo.example.socialas their handle.

Behind the scenes (I suppose), this would need to provision a PLC (there’s something for that?) using the credentials they already have for their organisational identity, then, it would need to resolve DNS queries for _atproto TXT queries (preferably, since the list of DIDs can grow pretty large for the HTTPS resolution) for each member who have opted in to get their handle. Right?

So, these are the two parts. I have never gotten the grasp on if/how atproto uses OIDC, which has confused me since the OAuth part is about authz and OIDC is authn. But I would suppose that if an organisation has OIDC, the OAuth flow is very similar to that of atproto, so it wouldn’t be a big deal to manage the identity through an OIDC system since OIDC is built on an OAuth authz flow. How would this work?

For the second part, I envision a CoreDNS plugin, where a bit of Go would be a generic module to answer those TXTqueries, and a non-generic part that queries the membership system for the username, and then some cache logic so that this query would not need to be performed for every DID resolution (because it is cached, right?) Does that sound reasonable? Does something like that already exist in the Bluesky stack?

1 Like

Trying to bring your own credentials to the PLC is not something I know how to do, but linking external accounts to an atproto DID, and hosting it if needed, might meet your needs.

I’m have an existing organization (openmeet.net) with non atproto users. I allow users to log in using their bluesky or atproto account if they have one, but half of them use google or email to log in today. I’m wrapping up changes to link these existing accounts to an atproto identity.

In the change, all users without a linked atproto account get a new DID and PDS that we host for them with a handle like username.opnmt.me. We hold their credentials for this identity until they decide to take over the account and/or move it elsewhere.

Now our users have an atproto identity, they can log in using their new handle, or continue using their web login, with an occasional oidc prompt with limited permissions to keep the two linked. They can use that identity to log into other atproto apps.

I think this is close to the model that tangled.sh uses and other apps are following. Is that what you’re after?

1 Like

So there is handlr which does the “Go DNS TXT queries” thing that you described, but it’s also generally not needed because the reference PDS ships with HTTP based handle resolution: https://emelias-test.bsky.social/.well-known/atproto-did

That works for all accounts out of the box, no need to provision txt records, since the PDS operates on both the root domain and all subdomains.

For cases where you have a different handle domain that is occupied with another application, there you’d probably use DNS, and systems like Aviary Domains help.

As for OIDC there’s currently no OIDC implementation within the PDS, but there’s no reason you couldn’t provision a PDS account with a password gated by an OIDC connecting app. Though you may want this for that: Feat: support disabling user registration unless admin by ThisIsMissEm · Pull Request #4464 · bluesky-social/atproto · GitHub (unless you use invite codes)

AT Protocol doesn’t use OIDC, just OAuth, though the reference implementation does borrow some OIDC concepts.

2 Likes

Yeah, that might actually be a better approach, I think I will consider that design!

1 Like

So there is handlr which does the “Go DNS TXT queries” thing that you described,

OK, great! I’ll look into that. I would probably not want to use HTTP for the backend, rather some database protocol, but that depends on the architecture of the backend.

but it’s also generally not needed because the reference PDS ships with HTTP based handle resolution: https://emelias-test.bsky.social/.well-known/atproto-did

Right, I’m aware. I’m just not sure it scales well with millions or tens of millions of accounts. One change, and you’d have to invalidate the cache, so you can’t meaningfully cache it, it’ll be much more infrastructure on both sides. Some hundreds or thousands, yes, but my gut feeling, I wouldn’t use it for millions.

That works for all accounts out of the box, no need to provision txt records, since the PDS operates on both the root domain and all subdomains.

Right, but I wouldn’t provision, it’s just a key-value lookup, very cheap stuff.

For cases where you have a different handle domain that is occupied with another application, there you’d probably use DNS, and systems like Aviary Domains help.

OK, that’s interesting!

As for OIDC there’s currently no OIDC implementation within the PDS, but there’s no reason you couldn’t provision a PDS account with a password gated by an OIDC connecting app. Though you may want this for that: Feat: support disabling user registration unless admin by ThisIsMissEm · Pull Request #4464 · bluesky-social/atproto · GitHub (unless you use invite codes)

Interesting! Actually, I wasn’t thinking about hosting my own PDS like tompscanlan does (well, we might in the future, but not for the first iteration), just a way to provision an account on existing PDSes in a very straightforward manner. So, the prompt=createyou did there is very relevant. However, I would need to make sure that they can only sign up with the username they gave us, otherwise, we’d have collisions. So, the question is whether they can use their credentials from us to sign up, or if we can enter the signup somehow with the username and domain supplied by us and just have them add some other credentials (like a password), or if we could do the whole signup flow in our system (probably not).

AT Protocol doesn’t use OIDC, just OAuth, though the reference implementation does borrow some OIDC concepts.

Right, that’s where my OIDC and OAuth understanding hits a limit :slight_smile: I would have thought OIDC would be the thing to use for the authen to obtain an ID Token, but I will need to read up on that.

1 Like

@kjetil.kjernsmo.net it does. In fact, it scales better than DNS from what I understand it, which is why Bluesky use HTTP handle resolution over DNS. Though @bnewbold.net or someone can probably comment better there.

The atproto-did only contains a single thing: what is the DID for this handle? So it can indeed be reasonably cached.

By “provision” I mean, something needs to create the DNS TXT records, they need to come from somewhere. Usually that means having to update DNS entries on a nameserver somewhere. Or you do that experimental handlr approach of being the DNS server yourself.

There are no usernames in AT Protocol, only handles, which are fully qualified. Currently there is no way to pass in a value to use as a “username” for OIDC’s prompt=create (at least, not a standardised way, some people have suggested using login_hint with this).

An account on an existing PDS would use one of it’s available handle domains, there’s no way you can tell an existing PDS “hey, register this user with my own handle domain”, instead what you would need to do is have the user registration complete, and then offer the ability to change handle to the desired handle (which requires an email consent).

1 Like

The atproto-did only contains a single thing: what is the DID for this handle? So it can indeed be reasonably cached.

Ah, OK, now I get it. Yes, indeed, that’ll work.

By “provision” I mean, something needs to create the DNS TXT records, they need to come from somewhere. Usually that means having to update DNS entries on a nameserver somewhere. Or you do that experimental handlr approach of being the DNS server yourself.

Yeah, so, we’re just not used to think about programming DNS servers like we program Web servers, but it can be done. Anyway, lets just leave it at that there’s more than one way to do it.

Now to the harder part:

However, I would need to make sure that they can only sign up with the username they gave us, otherwise, we’d have collisions.

There are no usernames in AT Protocol, only handles, which are fully qualified. Currently there is no way to pass in a value to use as a “username” for OIDC’s prompt=create (at least, not a standardised way, some people have suggested using login_hint with this).

Yeah, indeed, that’s what I meant when I said username and domain, what we’d pass would be the fully qualified handle.

An account on an existing PDS would use one of it’s available handle domains, there’s no way you can tell an existing PDS “hey, register this user with my own handle domain”, instead what you would need to do is have the user registration complete, and then offer the ability to change handle to the desired handle (which requires an email consent).

Right! Hmmmm, that’s the onboarding threshold I’m trying to lower, but I now I realize that requires some standardization.

So, basically, this comes from a conversation with @robin.berjon.com , where I was airing the idea of running a PDS for every handle domain, and he was like “don’t, just get them onto Eurosky, once we’re ready”. Which I’m happy to do, but I believe it is important to help the network effects work for us, in the sense that we’d need many parties manage the handles (decentralize it :wink: ), but that requires distributing trust between the PDSes and those managing the handles.

Say, there’s an operator pds.example.org and example.socialmakes a deal that their users may register with it. That deal could be made off-protocol, to add example.socialto their available handle domains list. However, it should only be available to users managed by example.social, so it needs to be an on-protocol way for ensure that pds.example.org doesn’t accept registrations from anyone else, and also that example.socialcan manage the provisioning from their own end. So, if user “foo” is in their system, they can simply click a button and get @foo.example.social, at most setting a separate password for that account.

That, I believe, would really make the onboarding smoother, and since you could have a lot more organizations help onboarding that way, it could really help grow the atmosphere.

Do you see any avenues for doing this kind of thing?