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

Allow IDP registration #240

Open
tplooker opened this issue Mar 31, 2022 · 189 comments
Open

Allow IDP registration #240

tplooker opened this issue Mar 31, 2022 · 189 comments
Labels
agenda+ Regular CG meeting agenda items design early interest okta

Comments

@tplooker
Copy link

TL;DR there is a significant amount of context at the start of this issue before we get to the proposal, here is a google doc version for an alternative form.

Background

The origins of many federated identity technologies have deep ties to providing an open ecosystem of IDPs to give End Users ample choice in how they choose to “login”. Efforts like OpenID v1 and v2, SIOP, Mozilla Persona, CHAPI, and others, strongly embodied these principles and much of this has remained in future revisions of standards such as OpenID Connect core. However, due to numerous complex issues, much of the industry today, primarily around the “social login” market has consolidated leaving a few IDPs as the dominant market players. To counteract this, FedCM in this work on establishing new browser mechanisms for supporting federated identity has an opportunity to make a meaningful impact and help re-chart the course for the future of federated identity on the web.

In the landscape of today, the choices around federated providers an End-User has available to them when going to “login” on the web is most often a small curated list of IDPs pre-determined by the Relying Party.

image

One of the main market forces that influences the options an End-User is presented with is often referred to as the NASCAR problem (https://github.com/fedidcg/FedCM/blob/main/explorations/related_problems.md#the-nascar-flag-problem). In order for a relying party to keep the UX on their login page from being overwhelming, they must pick a small number of IDPs to support (usually 2-3). How this decision is made by a relying party can be complex, but one major driving factor that applies to many is the existing user-base a particular IDP offers. Often the larger the user base, the more likely the relying party is in its desire to support it. This is because the relying party wants to offer as few login options as possible that services the largest possible user-base for them. This factor makes it difficult for new competition in the IDP side of the federated identity landscape, especially for entities that don’t have large pre-existing user-bases.

image

Who an IDP is, is often also important to factor in. As federated login technologies have developed, companies who built successful social networks, ISPs and commonly used search engines had the large user bases that made them attractive as IDPs to many Relying Parties. These IDPs have been very open about their interests in performing the IDP role, where the access it gives them to information about End User behavior, often supports their primary business models. In this context, concerns about user tracking are very real.

End Users looking to opt out of the limited federated identity login options available today are required to significantly compromise convenience because they are forced to manage a new set of credentials directly with the relying party, creating friction and usability challenges.

image

This equation in many cases has led to End Users using federated login options, trading off concerns such as the fear of being tracked by a particular IDP, for the convenience it offers. As a result, Relying Parties seeking large user bases continue to converge on the dominant IDPs and End User choice is further diminished. We end where we are today, in a self-reinforcing loop dominated by extremely limited choice at logon.

What we need to support instead is a federated login model that re-introduces the End-User into the mediation process so they can have more of a say on which provider they use and where.

Proposal

Currently the proposed FedCM API is focused around a browser mediated approach that assumes the relying party specifies a set of IDPs it supports login from. This model is largely a continuation of that described above and in many respects is just a browser mediated version of what we see most commonly on the web today.

image

Many Relying Parties will want to continue in a model where they specify the IDPs they support.

The challenge is for when this is not the case, to provide a viable way to achieve more End-User choice, greater inclusiveness, increased competition, and reduce vendor lock-in around the IDP options available.

In this proposed additional model, instead of the Relying Party specifying the IDPs it supports in the federation request, it communicates the capabilities it supports such as signature schemes, assertion formats and response modes.

End-Users can then register providers they wish to use with the browser, which are then available as options to present to the End-User when they go to login. This is enabled through the following two step process

  1. Registration Step - The End User navigates to the IDP they want to use, prior to attempting a login with an RP and registers it for use in the browser.

image

  1. Login Step - Later when the End User goes to login with a particular RP that supports this open IDP model, instead of the End User being presented with a pre-set list of IDPs determined by the RP, they are presented with a list of IDPs they have registered to use that support the capabilities required by the relying party.

image

Note - To prevent a scenario where a relying party is supporting this login model but no IDPs have been previously registered in the browser, the relying party could provide IDP hints.

image

Conclusions

Considering the cited basis for FedCM is to “preserve and elevate identity federation” please strongly consider adopting this in your work. Choosing this path would have a meaningful positive impact on federated identity on the web by improving the choices End-Users have to login on with. Ignoring this issue risks the continued consolidation of options available for End-Users and therefore undermining its value as a means of login.

Acknowledged Challenges

  • What happens to an end user when their registrations are wiped?
  • What happens if an end user has forgotten what IDP they use where?
  • Can a significant enough portion of relying parties trust login assertions from an IDP for which they don’t have a pre-existing trust relationship?
  • How are the capabilities supported by the RP communicated to the browser

Prior Art

CHAPI
Mozilla Persona
Account Chooser
OpenID

Raised with @dmitrizagidulin

@samuelgoto
Copy link
Collaborator

samuelgoto commented Mar 31, 2022

I strongly support this overall vision for FedCM, making it so that IDPs interoperate (e.g. don't require pre-registration).

We've been thinking along those lines too and calling it affectionally BYOIDP ("bring your own IDP"), as an analogy to how signing-up with email works (i.e. it is not like there is a list of email providers that the websites works with, right?).

As you may have guessed, we are deliberately not choosing to start there, because we have a responsibility to preserve the current deployment of federation, but we are in agreement of where it should/could go.

I don't think that the solution is as simple as you are making it seem (from a design of incentives perspective first, but also from a UX perspective second), but I think you got the problem and the broad strokes of how to go about it right.

Any chance you could come over some time at the FedID CG to present your work / proposal?

@tplooker
Copy link
Author

tplooker commented Mar 31, 2022

We've been thinking along those lines too and calling it affectionally BYOIDP ("bring your own IDP"), as an analogy to how signing-up with email works (i.e. it is not like there is a list of email providers that the websites works with, right?).

Yes very much aligned with this framing.

I don't think that the solution is as simple as you are making it seem (from a design of incentives perspective first, but also from a UX perspective second), but I think you got the problem and the broad strokes of how to go about it right.

Yes there are a bunch of additional incentives and UX complexities to consider here, some we have already discussed a bit but im sure there are others.

Any chance you could come over some time at the FedID CG to present your work / proposal?

Yes we would be more than happy to.

@samuelgoto
Copy link
Collaborator

Wonderful! @hlflanagan any chance you can help us coordinate a presentation by @tplooker sometime in the upcoming meetings that intersects with his availability?

@gffletch
Copy link

This model is very similar to the approach of decentralized identity. Rather than inventing something new, I highly recommend to look at making the browser be a viable "wallet" for the user and then just use decentralized identity protocols. Note that the OpenID Foundation is working in this space as well with the SIOPv2 spec and it's associated specs.

https://openid.net/specs/openid-connect-self-issued-v2-1_0.html
https://openid.net/specs/openid-connect-4-verifiable-presentations-1_0.html

@tplooker
Copy link
Author

@gffletch my mental model here is that the browser is a mediator able to facilitate an End-User using an IDP of their choosing (within the constraints of the RP of course). That IDP could be a "wallet" taking a variety of different forms such as a server/web application or native application. So the "browser" itself isn't the wallet. I also agree with the reference to prior art, SIOP in particular needs a solution to mediation beyond the limitations of a custom URL scheme such as "openid://"

@samuelgoto
Copy link
Collaborator

samuelgoto commented Apr 30, 2022

There were a series of sessions that happened at IIW between Kristina (SIOP) / Tobias (this proposal) / Dimitri (CHAPI) / Wayne (Sign-in with ethereum) and I (FedCM) on topics adjacent to this issue, and I feel like we left with a good amount of synergy and a reasonable sense of where to start from.

This is my personal recollection of what we discussed as a group at IIW, but others feel free to chime in and correct me where I'm wrong.

Overall, I left with the sentiment that we had a good amount of appreciation for each other's work.

As far as FedCM goes, SIOP aligns really well with FedCM because it addresses two key problems: (a) the portability problem and (b) keeping issuers blind to verifiers (through a self-issued and trusted OP).

FedCM aligns well with SIOP and CHAPI because both seem to need a neutral / reliable wallet-selector: SIOP has to name IDP on desktop browsers (e.g. if a user doesn't have a phone to scan a QR code) and iOS (e.g. without an openid:// disambiguator), and CHAPI requires everybody to trust auth.io and doesn't quite work in the absence of third party cookies.

The overall idea that we floated around at IIW (largely based on @tplooker 's original architecture) was to expose a browser API to allow:

(a) the registration of IDPs (Self-Issued OPs or not) and
(b) the ability of RPs to ask for an idtoken un-opinionated about where it is being issued from

It wasn't perfectly clear / obvious, but the intuition in the group was that the browser should just keep pushing things down to the OS level (which would obviously require further cooperation from OSes).

For (a) something along the lines of following would write into browser storage the IDP's registration:

navigator.credentials.registerProvider("https://my-idp.example");

This call registers with the Browser the IDP at "https://my-idp.example", which can have all sorts of configuration under a .well-known configuration. In the configuration, there would be some sort of callback that the IDP registers to be called when the IDP is chosen later.

We discussed a few UX options, and the most obvious one was to follow @tplooker 's original proposal to prompt at this point (this also matches what CHAPI does, so that's encouraging). We discussed a few more options and generally agreed that this needs more experimentation to determine what would work best.

For (b), FedCM could expose an extra option to allow, not only named IDPs, but also allowing the user to bring their own. Something along the lines of:

const credential = await navigator.credentials.get({
  federated: {
    providers: [{
      // allows the account chooser to load named IDPs
      url: 'https://named-idp.example',   
      clientId: '********'
    }],
    // The RP accepts IDPs that called registerIDP() before.
    registered: true, 
    // the RP accepts SIOPs
    selfIssued: true,
  }
})

And, when invoked in this fashion, the account chooser would bring accounts from "named" IDPs as well as "registered" IDPs.

If a "registered" IDP is called, then the callback previously registered is called.

We also discussed how this could be used to pass VCs/mDLs over SIOP, which didn't seem to conflict/disagree with this architectural choice. One of the challenges that Wayne brought up that I don't think we talked about enough was to have the ability to register not just IDPs but also types. Something along the lines of:

navigator.credentials.registerProvider("https://my-idp.example", [
  "UniversityDegree", "DriversLicense", "COVIDVaccine", ...
]);

Such that the RP could then use a querying language to filter out SIOPs that contain them.

We also discussed briefly that we'd like the resulting idtoken to be directed, so it is likely that the callback needs to take at least the RP's name so that the SIOP server can direct it.

There is a lot of handwaving here, but this is more or less what I remember from the discussion. There were a series of diagrams that we drew in the whiteboard, and in case any of you still have them on your phones, sharing them would be appreciated.

@Sakurann
Copy link

Sakurann commented May 1, 2022

Pictures of the whiteboard we drew:
2E574CD0-3323-401F-9804-3CC19064E4CE
0D638E94-F09E-45E2-93A1-7FD19A62AF08
DD675404-4117-4C17-A8F1-78104FA85EAA
832C11D7-1745-4930-9720-499AC1AA0DA2
7C379B53-03E0-40CB-B7FF-950DD285EF9A

@quartzjer
Copy link

This all looks and sounds pretty fantastic, wish I had been there!

We also discussed briefly that we'd like the resulting idtoken to be directed, so it is likely that the callback needs to take at least the RP's name so that the SIOP server can direct it.

Not just directed, but a nonce would be essential for the resulting token to be bound and prevent replay as well. Signed requests will also be an important trust mechanism, so the RP initiation interface might be fairly rich.

@dlongley
Copy link

dlongley commented May 2, 2022

Instead of taking this approach:

navigator.credentials.registerProvider("https://my-idp.example", [
  "UniversityDegree", "DriversLicense", "COVIDVaccine", ...
]);

I'd recommend that any sort of filters be provided / be updateable either through some .well-known config or manifest.json. Providers should not require the user to visit their site and call registerProvider again to make changes / improvements to what it is supported. Browsers should pull down config updates from time to time -- and needn't do it on demand (in the middle of a particular user request) if that would be a privacy concern.

Keeping the registration API surface light (i.e., base URL as the only param) also enables better future proofing for adding new feature expression via configs / manifest.json over time.

I will note that adding filters for specific Verifiable Credential types may have challenges, given the unbounded set size. Certainly being able to specify that a provider supports VCs at all or the ability to produce Verifiable Presentations (or perhaps provides other types of credentials / supports other features / protocols) could be of value. So there are some additional considerations around what is to be filtered and at what "levels" or granularity.

@samuelgoto
Copy link
Collaborator

I'd recommend that any sort of filters be provided / be updateable either through some .well-known config or manifest.json.

Ah, that would work too!

So, something along the lines of:

navigator.credentials.registerProvider("https://my-idp.example");

Which, as a convention, points towards something like:

https://my-idp.example/.well-known/tbd.json

Which could contain:

{
  "typesOfCredentialsICanProvide": [
    "UniversityDegree", "DriversLicense", "COVIDVaccine", 
  ]
}

Did I understand that right?

@dlongley
Copy link

dlongley commented May 2, 2022

@samuelgoto,

Did I understand that right?

Yes! Thanks.

@bvandersloot-mozilla
Copy link
Collaborator

I think a simple version of the bring-your-own IDP is interesting, where a user can use an arbitrary identity with a site. This would be akin to a wildcard in the provider list that searches through the users' preregistrations. This could be useful for RPs that need no guarantee of identity elements, just a unique identifier– especially if they don't want to deal with handling username-password management.

@samuelgoto
Copy link
Collaborator

Just to report back on this thread with an update, we started looking into this problem and building some prototypes to see where that takes us: Firefox seems initially supportive and it shows up in multiple places, e.g. #374.

You can follow the prototype process and some early ideas on API design here: https://bugs.chromium.org/p/chromium/issues/detail?id=1406698.

@michielbdejong
Copy link

@samuelgoto It was great to discuss this in person last week at TPAC!
I would love to help prototype the BYOIDP idea, I see it would have the following advantages:

  • solve the NASCAR problem
  • make it feasible to have thousands of acceptable IDPs, especially for instance in Research and Education
  • support things like https://indieauth.com/ and "Log in with your WebID" (as used in https://solidproject.org) without requiring the user to type in the domain name of their IDP
@thhck
Copy link

thhck commented Oct 27, 2023

Hello,

@janschill and I are Solid developers, and we believe this proposal would be a great feature for FedCM to integrate well with the Solid ecosystem.

We're considering working on a Proof of Concept to explore potential solutions and understand the practical challenges.

You can follow the prototype process and some early ideas on API design here: https://bugs.chromium.org/p/chromium/issues/detail?id=1406698.

@samuelgoto it seems that there has been no update since Feb 15. What is the status of the prototype?

Is anyone else currently working on it?

Otherwise, we are looking forward to the possibility of contributing to this effort, and we'd appreciate any guidance or feedback you could provide to help us get started.

@samuelgoto
Copy link
Collaborator

We're considering working on a Proof of Concept to explore potential solutions and understand the practical challenges.

I'd love to participate in this. Is there a call that I can join or maybe a document that I can read to learn more about what you have in mind?

@samuelgoto it seems that there has been no update since Feb 15. What is the status of the prototype?

We have a basic prototype working in chrome canaries that anyone can try.

We are currently blocked on getting feedback from developers if the current proposal meets needs and is a useful API.

Any chance you'd be willing to give this a go and let us know if it works the way you'd expect it to work?

Is anyone else currently working on it?

Not at the moment. Like I said, we feel blocked by meaningful developer's interest.

Otherwise, we are looking forward to the possibility of contributing to this effort, and we'd appreciate any guidance or feedback you could provide to help us get started.

I think one first concrete step we could take is getting a better sense of:

(a) what problem you currently have that you feel like this feature would help?
(b) what alternatives you considered?
(c) how many users/developers would benefit from this feature?

At the moment, we feel like this would be a great addition to FedCM, but we are really worried about implementing and shipping something that doesn't get enough use (and then, paying a maintenance price). We are willing to take risks, but that's currently what's holding us back moving forward, so the more data points you can give us about market demand the easier we can make this happen.

@thhck
Copy link

thhck commented Oct 29, 2023

I'd love to participate in this. Is there a call that I can join or maybe a document that I can read to learn more about what you have in mind?

We want to improve user experience within the SoLiD ecosystem. Given the multitude of IdPs, it can be challenging for users often to recall their specific IdP. If browsers could display a list of previously used IdPs, it would significantly enhance the user experience and usability. We would love to dive deeper in this topic during a call. We also started working on a PoC.

We have a basic prototype working in chrome canaries that anyone can try.

We are currently blocked on getting feedback from developers if the current proposal meets needs and is a useful API.

Any chance you'd be willing to give this a go and let us know if it works the way you'd expect it to work?

We downloaded the latest version of chrome canary on MacOS activated the required flags ( including fedcm-idp-registration ) but we were not able to make it work.
We didn't found the api call to register an IdP, and calling the following didn't gave us any result:

navigator.credentials.get({
  identity: {
    providers: [{
      registered: true 
    }]
  }
});

Is there any resources on how to make it work ?

(a) what problem you currently have that you feel this feature would help?

  • To interact with an IdP, RPs must provide a text input where users can enter their IdP URL.
    • Users have to manually enter the IdP URL and need to remember it, ensuring they make no typos.
    • If a user has multiple IdPs, they must remember all the corresponding URLs.

(b) what alternatives you considered?

  • We've thought about a browser extension, but it's not ideal because it needs to be installed on each browser.
  • Field autocomplete was considered, but it doesn't offer an experience as seamless as the one FedCM provides.

(c) how many users/developers would benefit from this feature?

  • It's difficult for us to estimate these numbers. Undoubtedly, this feature would be a significant improvement for the Solid ecosystem. However, I believe it would also be highly beneficial for larger and more mature decentralized communities ( I'm thinking of the Fediverse).
@npm1
Copy link
Collaborator

npm1 commented Oct 30, 2023

I'm not super familiar with the flag but I think the prototype is not usable yet. You can call IdentityProvider.register('configUrl') in an IDP context but it does nothing as far as I can tell.

@samuelgoto
Copy link
Collaborator

We want to improve user experience within the SoLiD ecosystem. Given the multitude of IdPs, it can be challenging for users often to recall their specific IdP. If browsers could display a list of previously used IdPs, it would significantly enhance the user experience and usability.

Can you expand on this a bit more (just intuition is fine, we don't need super hard data at this point)? How many IdPs are operating today within the Solid ecosystem? How many users a typical IdP have? How many solid RPs exist, and how often are they used?

We also started working on a PoC.

This is really neat, and typically a strong signal that browser vendors take to make an assessment of demand: are developers going out of their way to try to make this work.

Is there an open source implementation of Solid that we could use to build some of these prototypes?

We downloaded the latest version of chrome canary on MacOS activated the required flags ( including fedcm-idp-registration ) but we were not able to make it work.
We didn't found the api call to register an IdP, and calling the following didn't gave us any result:

Ah, I think I'm still missing merging one more CL. Let me get that merged and report back to you here.

However, I believe it would also be highly beneficial for larger and more mature decentralized communities ( I'm thinking of the Fediverse).

Yeah, I share that intuition. But we really need to make sure that we are developing something that will be ultimately useful for users and developers, because the cost of development and maintenance is extremely high.

I think we'd be happy to move forward trying to complete prototypes and seeing where that takes us, but we are ultimately going to need a good set of developers who are excited about this before moving too far. Fair?

aarongable pushed a commit to chromium/chromium that referenced this issue Nov 17, 2023
In this CL (behind a flag), we use the permission context that was
written in part 1 to insert IdPs that were registered, and expose a JS API that allows an RP to refer to the registered IdPs.

Prototypes a proposal to solve the following bug [1] to allow us to
gather guidance from developer if this is directionally correct.

[1] fedidcg/FedCM#240 (comment)

Design Doc: https://docs.google.com/document/d/1MKpxTTLi-1e5-0brsdy50TVk2YM9AghoL3diSpRv_vE/edit#heading=h.jdxq4526c2ip

Change-Id: Id1bf4b2590ce55fcd6b8a50edcabe54abb652fc1
Bug: 1406698
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4163707
Reviewed-by: Yi Gu <yigu@chromium.org>
Reviewed-by: Mustafa Emre Acer <meacer@chromium.org>
Commit-Queue: Sam Goto <goto@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1226397}
@samuelgoto
Copy link
Collaborator

@thhck I just merged a CL in chromium that implements some of the missing parts that you ran into. Can you try to use it in Chrome Canaries in a couple of days once it picks it up?

@janschill
Copy link
Contributor

@samuelgoto I work with @thhck on this. I just tested this in Google Chrome Canary and it works.

I ran the demo IdP from @asr-enid with two IdPs, registered, logged into idp-1.localhost and in a Chrome console ran:

IdentityProvider.register('http://idp-1.localhost:8080/fedcm.json');

navigator.credentials.get({
  identity: {
    providers: [{
      nonce: "not-a-nonce",
      configURL: "http://idp-2.localhost:8080/fedcm.json",
      clientId: "yourClientID",
      registered: true
    }]
  }
});

The browser then successfully prompted me with "Sign in to idp-1.localhost with idp-1.localhost".

Thanks for getting this out.

@achimschloss
Copy link
Contributor

I ran the demo IdP from @asr-enid with two IdPs, registered, logged into idp-1.localhost and in a Chrome console ran:

Great to see that this is useful beyond our own usage!

@samuelgoto
Copy link
Collaborator

@samuelgoto I work with @thhck on this. I just tested this in Google Chrome Canary and it works.

Can you try this again? The code snippet you sent feels off to me: you want to skip the configURL when using registered: true.

For example:

IdentityProvider.register('http://idp-1.localhost:8080/fedcm.json');

navigator.credentials.get({
  identity: {
    providers: [{
      nonce: "not-a-nonce",
      // comment out the following line, so that the browser can load accounts 
      // from registered IdPs rather than by configURL
      // configURL: "http://idp-2.localhost:8080/fedcm.json",
      clientId: "yourClientID",
      registered: true
    }]
  }
});
@janschill
Copy link
Contributor

@samuelgoto yeah, that was also my understanding. I get this error though.

image

I am on Google Chrome Canary: Version 121.0.6153.0 (Official Build) canary (x86_64)

image

The FedCM prompt shows only after the last get call where I also provide the configURL, please note that it doesn't matter what the passed value is, it just seems that configURL is not an optional parameter in your implementation.

@sebadob
Copy link

sebadob commented May 25, 2024

I implemented a working version into Rauthy and just wanted to provide some feedback.

It is working pretty good so far with static pre-registered and dynamic ephemeral clients after a lot trying to debug things, which was pretty hard to do. I ran into some issues and have some open questions.

IdP registration status

I don't know if such a functionality exists, but is it possible to do a registration clean up for an origin or list all registered IdP's? This would be important for 2 reasons:

  1. I did some "bad" registrations during testing on localhost, which screwed up the tests further down the road. I had very weird issues (like the one from @philsmart above) that it was not able to fetch the config, even though the URL and everything was correct. It seems to me that the FedCM internally just iterated over the list of registered providers, reached a bad / broken one and then stopped. This means when I had a bad registration, it would not let me log in any more even on a test UI I created that works on its own. I only found this out after doing tests with self-signed TLS locallay, which the FedCM complained about as well. But after these, I got the same TLS error message in a proper environment which brought me onto this.
    To fix this, in the end I fully removed the browser from the OS and rm -rfed ~/.config/google-chrome-unstable. After a new installation of the browser, I had everything clean again and the errors went away. If it behaves like I suspect, it would be nice if it would simply skip failing configs, ignore them and move on with the list to not break existing ones.

  2. It would be good if we would be able to check if "our" origin is already registered, because then there would be no point in even showing such a button to the user, which in the end provides a better UX.

Ephemeral / dynamic clients

As mentioned already, it is working fine with ephemeral clients so far. You simply provide a URL pointing to a JSON in the correct format and that's it. Rauthy will then fetch this document and try to deserialize it into a format that is based on the OIDC Dynamic Client Regsitration spec: https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata

The struct with proper validation in my code looks like this:

pub struct EphemeralClientRequest {
    #[validate(regex(
        path = "RE_CLIENT_ID_EPHEMERAL",
        code = "^[a-zA-Z0-9,.:/_\\-&?=~#!$'()*+%]{2,256}$"
    ))]
    pub client_id: String,
    /// Validation: `[a-zA-Z0-9À-ÿ-\\s]{2,128}`
    #[validate(regex(path = "RE_CLIENT_NAME", code = "[a-zA-Z0-9À-ÿ-\\s]{2,128}"))]
    pub client_name: Option<String>,
    /// Validation: `[a-zA-Z0-9,.:/_-&?=~#!$'()*+%]+$`
    #[validate(regex(path = "RE_URI", code = "[a-zA-Z0-9,.:/_-&?=~#!$'()*+%]+$"))]
    pub client_uri: Option<String>,
    /// Validation: `Vec<^[a-zA-Z0-9\+.@/]{0,48}$>`
    #[validate(custom(function = "validate_vec_contact"))]
    pub contacts: Option<Vec<String>>,
    /// Validation: `Vec<^[a-zA-Z0-9,.:/_\\-&?=~#!$'()*+%]+$>`
    #[validate(custom(function = "validate_vec_uri"))]
    pub redirect_uris: Vec<String>,
    /// Validation: `Vec<^[a-zA-Z0-9,.:/_\\-&?=~#!$'()*+%]+$>`
    #[validate(custom(function = "validate_vec_uri"))]
    pub post_logout_redirect_uris: Option<Vec<String>>,
    /// Validation: `Vec<^(authorization_code|client_credentials|password|refresh_token)$>`
    #[validate(custom(function = "validate_vec_grant_type"))]
    pub grant_types: Option<Vec<String>>,
    /// Validation: `60 <= access_token_lifetime <= 86400`
    #[validate(range(min = 60, max = 86400))]
    pub default_max_age: Option<i32>,
    /// Validation: `[a-z0-9-_/:\s*]{0,512}`
    #[validate(regex(path = "RE_SCOPE_SPACE", code = "[a-z0-9-_/:\\s*]{0,512}"))]
    pub scope: Option<String>,
    pub require_auth_time: Option<bool>,

    /// Validation: `^(RS256|RS384|RS512|EdDSA)$`
    pub access_token_signed_response_alg: Option<JwkKeyPairAlg>,
    /// Validation: `^(RS256|RS384|RS512|EdDSA)$`
    pub id_token_signed_response_alg: Option<JwkKeyPairAlg>,
}

When Rauthy receives a URI as client_id, it will fetch this document and use the result (on success) as the client. The origin sent via FedCM during the assertion will be matched against the allowed redirect uri's in this document. This makes it possible to use the same config for a traditional OIDC flow as well as for FedCM in this example.
If on the other hand it receives a non-URI as client_id, it assumes the request wants to use a static client and will do a database lookup instead.

This is working fine in first tests so far. There is no real performance issue either, because the IdP can cache these fetches. There is not really a need to register a client dynamically in this case, apart from then having the ability to use a confidential one like in OAuth / OIDC.

For an ephemeral client, the client_id must match the URI where it is hosted and vice versa the client_id must point to the URI where the JSON document can be fetched from. Rauthy will append accept: application/json.

The assertion response

I know there is the open issue about it, but I just wanted to quickly share a thought about this.
Right now, I am simply returning the id_token as the token from the assertion endpoint. This is the one that makes the most sense to me right now, because I can only return one of them.
However, it would be very beneficial to expand this response like mentioned in the other issue about it, because then we could for instance return an auth code to the RP. This would make it possible to use confidential clients with an additional secret again. Or returning access_token + id_token would be helpful, if the RP would want to do online validation and send a request to the /userinfo for very sensitive endpoints and such things.
All of the additional values could maybe just optional and the RP can decide, what it wants to use them for and how. If for instance only a token or access_token would be mandatory, it would not destroy the current behaviour for simple clients, and at the same time allow more sophisticated IdP's to return more valuable data to an RP.

The FedCM internal login state

I had quite a bit of trouble with this. When I was logged in beforehand already, everything was fine. The problem came up, when I deleted my session cookies, so I would be logged out. With the next request to the /accounts, where I return the Set-Login header properly, FedCM would notice that I was logged out and log an error in the console. The problem then was, that even when I logged in manually, it would not catch this, because it would not even try another request to the /accounts. I needed to manually return the Set-Login from other endpoints like the login, token, session / userinfo, and so on. Only then the browser would update the state and not complain any more.
I basically append the Set-Login header in a lot of places where it just makes sense to always keep the FedCM API happy and up to date, even when it's not actively used at that moment.

But this problem maybe only exists because one issue I am left with, where I am stuck right now:
When I am in logged-out state, the FedCM does not open the login_url in a new window like expected. It just logs an error into the console that I am logged out, that's it. I saw this window once in the beginning, but now its gone and I can't get it back.
Does anyone have an idea why and what I might be doing wrong?

Testing

You could test it on my instance yourself, if you like.

I deployed a dedicated test-instance just for FedCM:
https://iam.sebadob.dev/auth/v1/fedcm

You would need to create an account (easiest by just signing in with Github):
https://iam.sebadob.dev/auth/v1/account

The instance provides a sample config for ephemeral client testing as well:
https://iam.sebadob.dev/auth/v1/fed_cm/client_config

The test UI and IdP are on the same origin right now, but it should work the same when they are separated. I will create a dedicated test RP deployment when I fixed the login issue.

As mentioned above, the only bigger problem I am left with is that the login window does not pop up, if we are actually in logged-out state. I would appreciate some help with this.

@anderspitman
Copy link

anderspitman commented May 26, 2024

@sebadob can't remember if I already clarified this or not, but I believe the auto login popup is only intended for cases where the login state is out of sync, ie FedCM thinks you're logged in but you're not (maybe you manually deleted cookies), and it attempts to retrieve the list of accounts and gets a 401. At least I can reproduce this with my implementation by deleting login cookies on my IdP. Others can correct me if I'm wrong about this.

@sebadob
Copy link

sebadob commented May 26, 2024

@sebadob can't remember if I already clarified this or not, but I believe the auto login popup is only intended for cases where the login state is out of sync, ie FedCM thinks you're logged in but you're not (maybe you manually deleted cookies), and it attempts to retrieve the list of accounts and gets a 401. At least I can reproduce this with my implementation by deleting login cookies on my IdP. Others can correct me if I'm wrong about this.

So this means, if I am logged out, the FedCM would simply stop working (for that IdP) and it doesn't even provide me any link or action where it would provide a way of logging in again? So, the user would need to remember some IdP, go there manually in a new tab, login and then back to the original page?

I just tried it the way you described, and the window still did not pop up. No matter if I am logging out on the normal way while the backend returns the Set-Login: logged-out, or if I just delete cookies, so the state it out of sync. FedCM will be in sync again as soon at it fetches the /accounts, where this header is returned as well.
I still only see Not signed in with the identity provider. in the console with not window pop up, Actually, not even the small one with the account selection comes up. It just stops the execution silently somehow.

@philsmart
Copy link
Contributor

philsmart commented May 28, 2024

@sebadob, you'll need to enable the 'button mode' API (chrome://flags/#fedcm-button-mode) and configure the 'button' flow in your credential options request to have it pop up a window if you have not set the logged-in status of your IdP.

@sebadob
Copy link

sebadob commented May 28, 2024

@philsmart that did the trick.

I wasn't aware of the 2 different modes, but its pretty cool that you could use widget as long as the user is logged in and fall back to a login button if not.

Thanks a lot!

@samuelgoto
Copy link
Collaborator

@sebadob thank you so much for giving this a try!!!

I'm trying to break down #240 (comment) into smaller parts, here it goes:

IdP registration status
I don't know if such a functionality exists, but is it possible to do a registration clean up for an origin or list all registered IdP's? This would be important for 2 reasons:

That's a great point, and something that I ran into myself too. I kick this off here #606 to discuss this feature independently from this large thread.

Ephemeral / dynamic clients
As mentioned already, it is working fine with ephemeral clients so far.

I'm not able to fully follow this section. Is there something that you think isn't working that FedCM could act on, or did you manage to make it work under these different circumstances?

The assertion response
I know there is the open issue about it, but I just wanted to quickly share a thought about this.

Yeah, I hear you. We are tracking that here: #578

The FedCM internal login state
I had quite a bit of trouble with this. When I was logged in beforehand already, everything was fine. The problem came up, when I deleted my session cookies, so I would be logged out.

Yeah, as suggested by others above, I think that the #442 will cover this problem.

@sebadob
Copy link

sebadob commented May 28, 2024

I'm not able to fully follow this section. Is there something that you think isn't working that FedCM could act on, or did you manage to make it work under these different circumstances?

@samuelgoto No everything is absolutely fine. You can share and self-manage the JSON document and don't need any upfront registration, its working very nicely.
I just wanted to share how I am doing it.

I released Rauthy v0.23.2 today which can act as a FedCM IdP with the above mentioned features, if you enable the support in the config.
I really like the UX for FedCM. I am looking forward to have this supported in all browsers at some point. It kind of feels a little bit like magic, because you don't have the typical redirections as you do with oauth / oidc. Reminds me a bit of the passkeys experience when I first tried them back then.

@samuelgoto
Copy link
Collaborator

Just wanted to report back to this thread here another independent developer that managed to expose themselves as a FedCM IndieAuth IdP here.

You can follow this thread here to read how they got through it:

https://x.com/Paul_Kinlan/status/1793947618831114685

GOVhyI3WAAAEbit

@anderspitman
Copy link

anderspitman commented Jun 8, 2024

@aaronpk I'm working on making LastLogin compatible with webmention.io's FedCM implementation. I'm returning the following from my ID assertion endpoint:

{"token":"{\"code\":\"dummy_code\",\"metadata_endpoint\":\"https://anderspitman.com/.well-known/oauth-authorization-server\"}"}

But I'm never seeing any requests to the metadata endpoint after that and the login fails. Any ideas?

@samuelgoto
Copy link
Collaborator

samuelgoto commented Jun 8, 2024

But I'm never seeing any requests to the metadata endpoint after that and the login fails. Any ideas?

The metadata endpoint isn't the oauth endpoint, it is the Indie Auth metadata endpoint.

UPDATE: this isn't correct. They are actually the same.

@aaronpk
Copy link

aaronpk commented Jun 8, 2024

@anderspitman can you check the dev console for any errors? You should see that JSON in the dev console too logged from here https://github.com/aaronpk/webmention.io/blob/main/public/js/fedcm.js#L45

@anderspitman
Copy link

The metadata endpoint isn't the oauth endpoint, it is the Indie Auth metadata endpoint.

The IndieAuth metadata endpoint is standard OAuth2 metadata, so it should be ok.

@anderspitman
Copy link

@anderspitman can you check the dev console for any errors? You should see that JSON in the dev console too logged from here https://github.com/aaronpk/webmention.io/blob/main/public/js/fedcm.js#L45

Hmm it doesn't seem to be making it that far

DeepinScreenshot_select-area_20240608090720

@anderspitman
Copy link

I tried a complete reset of Chrome canary as well, deleting all config and cache information and starting fresh.

@anderspitman
Copy link

anderspitman commented Jun 8, 2024

There's currently no security set up on this. You can confirm with the following curl whether I'm returning the correct info:

curl https://anderspitman.com/fedcm/id-assertion -H "Sec-Fetch-Dest: webidentity" -d "client_id=https://webmention.io/id" -H "Origin: https://webmention.io" -v
@samuelgoto
Copy link
Collaborator

I found it useful to follow the code here while setting up my Indie Auth server:

aaronpk/webmention.io@845e07d#diff-03f47d5ece0f94de79c49a98d1268d8cb0906dab35d2f8a919f63d7d995456e1R111

@aaronpk
Copy link

aaronpk commented Jun 8, 2024

That looks to me like Chrome is rejecting the response from the ID assertion endpoint before it ever gets to the JS. Probably something wrong with the CORS headers.

I do wish Chrome was a little more verbose on the error, because ERR_FAILED could be anything from no IP address found to rejected because of the HTTP headers not being right according to FedCM.

@samuelgoto
Copy link
Collaborator

That looks to me like Chrome is rejecting the response from the ID assertion endpoint before it ever gets to the JS. Probably something wrong with the CORS headers.

You can easily test this theory by calling the FedCM API directly (e.g. using the developer console), rather than by loading webmention.io.

I do wish Chrome was a little more verbose on the error, because ERR_FAILED could be anything from no IP address found to rejected because of the HTTP headers not being right according to FedCM

Yeah, we are starting to work on making debugging better. Agreed that it currently is lacking a lot.

@anderspitman
Copy link

anderspitman commented Jun 8, 2024

That looks to me like Chrome is rejecting the response from the ID assertion endpoint before it ever gets to the JS. Probably something wrong with the CORS headers.

Good call. I was setting Access-Control-Allow-Origin directly to the client ID, which is https://webmention.io/id, which is not a valid Origin. Needed to parse it first and extract the domain.

Thanks!

@anderspitman
Copy link

anderspitman commented Jun 14, 2024

If anyone wants to try logging in to webmention.io with FedCM and your own domain, without needing to host your own server, here's some somewhat clunky steps:

  1. Use Chrome Canary 128+
  2. Go to https://lastlogin.net/login and add an identity
  3. Go to https://lastlogin.net/domains and follow the instructions to point your domain at lastlogin.net. Subdomains aren't yet supported, so you'll need an extra eTLD+1 laying around.
  4. Refresh the page until it loads properly. You're now on the same servers as lastlogin.net, but accessing it through your own domain.
  5. Go to /login and add the identity again.
  6. Click "Register FedCM" at the top of the page and allow.
  7. Navigate to webmention.io. You should be able to log in with FedCM.

EDIT: You'll also need to go to chrome://flags, search for "fedcm", and enable IdP registration and multi-IdP support.

@samuelgoto
Copy link
Collaborator

samuelgoto commented Jun 15, 2024

If anyone wants to try logging in to webmention.io

This is really cool, good stuff @anderspitman !!

@npm1
Copy link
Collaborator

npm1 commented Jun 17, 2024

Reminder to please also enable the multiIDP flag when playing with IDP registration. Since we may show multi IDP UI when requesting registered IDPs, we require the multi IDP flag to be enabled.

@anderspitman
Copy link

Reminder to please also enable the multiIDP flag when playing with IDP registration. Since we may show multi IDP UI when requesting registered IDPs, we require the multi IDP flag to be enabled.

Good point. I forgot to mention setting the necessary chrome flags. I just updated my comment. Both IdP registration and multi IdP are required, right?

@npm1
Copy link
Collaborator

npm1 commented Jun 17, 2024

Reminder to please also enable the multiIDP flag when playing with IDP registration. Since we may show multi IDP UI when requesting registered IDPs, we require the multi IDP flag to be enabled.

Good point. I forgot to mention setting the necessary chrome flags. I just updated my comment. Both IdP registration and multi IdP are required, right?

Yep!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agenda+ Regular CG meeting agenda items design early interest okta