Skip to content

fedidcg/login-element

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 

Repository files navigation

Author: @samuelgoto Date: Jan 12, 2026 Status: early draft

With a massive amount of guidance from Philip Jägenstedt (on relationship to <search>, <main>, ARIA and microdata), Jeffrey Yasskin (on relationship to <geolocation> and <permission> and JSON-LD, as well as the various trade-offs between inline elements and modal dialogs) Khushal Sagar (on relationship to WebMCP), Ryan Levering (on relationship to schema.org), Christian Biesinger and Dominic Farolino (on a variety of HTML design choices) and Nina Satragno (on the relationship to WebAuthn).

The <login> element

TL;DR; every website has to create their own login flow, leading to an inconsistent, fragmented, inneficient and cumbersome user experience. This is a proposal to allow website authors to introduce an inline <login> element to wrap their "login" links typically found on the top right corner on their pages and provide a browser mediated and unified login flow across all authentication mechanisms (notably passwords, passkeys and federation) across every website. <login> renders like an <a> wrapping its inner content and opens a mediated modal dialog when clicked on with all login options available with a corresponding Credential Management API. The Credential Management call is constructed according to the options declared inline declaratively with a new <credential> element, which can represent all of the supported credential types. In addition to the user experience benefits, the declarative <login> element allows browsers to pull login out of the content area into the browser area to, for example, re-use preferences across sites, display in browser UI (e.g. the URL bar) and discover login options in agentic browser flows.

<login oncomplete="login()">
  <credential type="publickey" challenge="1234" rpId="example.com" userVerification="preferred"></credential>
  <credential type="federated" clientId="1234" configURL="https://idp1.example/config"></credential>
  <credential type="federated" clientId="5678" configURL="https://idp2.example/config"></credential>
  <a href="login.html">login</a>
</login>

This gets transpiled into the following in supporting browsers:

<span onclick="navigator.credentials.get({publicKey: ..., identity: ...}).then((credential) => {this.credential = credential; login();})">
  <a href="login.html">login</a>
</span>

And degrades gracefully to the following in browsers without native support:

<span>
  <a href="login.html">login</a>
</span>

Problem Statement

One of the most common patterns on the Web is to allow users to login to websites.

Login typically starts with a "login" link, commonly available on the top-right corner of websites which usually leads to what's known as the NASCAR flag UI: When users interact with the NASCAR flag UI, they have to guess what to use between the various options: do I have a passkey? a password? or did I click in one of these social login options before?

Because the NASCAR flag is implemented in userland, it can't (by design) reconcile and unify across the various login methods, leading to confusion and friction at best and account duplication at worst.

Fortunately, browsers have been able to mediate more and more of the login flows, starting from some of the earliest attemps with BasicAuth but more recently with the advent of modern APIs such as WebAuthn (a strong alternative to passwords), WebOTP (for verifying phone numbers), FedCM (for federation), Digital Credentials (for government-issued IDs) and Email verification Protocol (for verifying email addresses), all exposed via the Credential Management API.

While, for the most part, each of these credentials have been deployed independently, they have been deliberately designed as Credential Management credential types with the hope that we would be able to unify them at some point. One recent such step is via the immediate mediation proposal, which allows websites to get an account chooser that unifies across passwords/passkeys and social login.

However, because immediate mediation is an imperative API call, the browser can't use it outside of its content area, for example in a common browser UI area (e.g. the URL bar) or in agentic flows (e.g. when an LLM is helping the user login).

To further unify and reconcile across authentication mechanisms, would it be possible to create a declarative browser-mediated login flow that websites could use before users even get to the NASCAR flag UI?

Goals

There are many conflicting goals that we are navigating, but here are a few that we have found useful to constrain the solution space:

  • Must cover the most common login mechanisms, specifically passwords/passkeys and federation
  • Must allow website authors to provide declarative login semantics to browsers (to allow use outside of the content area, e.g. the url bar or agentic browsing)
  • Must be able to be retrofited into existing websites (e.g. support feature detection)

Proposal

The proposal is to introduce a <login> element (along with a <credential> element) that can declaratively describe an imperative Credential Management API call, along the lines of <geolocation>.

We are still trying to figure out what are the right semantics, but one intuition is that <login> could work like <a> elements: an inline element that renders its inner contents and performs an action when users click on it.

The intention is to replace the typical "login" links that show up on the top right corner of websites with the following:

<login oncomplete="login()">
  <credential type="publickey" challenge="1234" rpId="example.com" userVerification="preferred"></credential>
  <credential type="federated" clientId="1234" configURL="https://idp1.example/config"></credential>
  <credential type="federated" clientId="5678" configURL="https://idp2.example/config"></credential>
  <a href="login.html">login</a>
</login>

When clicked, a modal dialog is shown, with a browser mediated unified account chooser that contains all of the options specified by the developer.

Sequencing

Phase 1

While a unified modal dialog for login seems like a great end state, it doesn't quite seem like something that is quite within reach today: immediate mediation is still unresolved and the developer demand for a unified account chooser is still in its infancy.

One way that occurred to us that we could take a smaller and concrete step towards the right direction is to wrap the individual options in the NASCAR flag, rather than the top right corner login link.

So, for example, as opposed to replacing the "login" top right corner links, we'd replace the individual passkeys buttons in the NASCAR flag:

<login oncomplete="login()">
  <credential type="publickey" challenge="1234" rpId="example.com" userVerification="preferred">
    <a onclick="navigator.credentials.get({publicKey: ...})">Sign-in with a Passkey</a>
  </credential>  
</login>

And the following for social login buttons:

<login oncomplete="login()">
  <credential type="federated" clientId="1234" configURL="https://idp1.example/config">
    <a onclick="navigator.credentials.get({identity: ...})">Sign-in with IdP</a>
  </credential>  
</login>

This would allow us to introduce <login> for each of these individual mechanisms independently while working our way towards a unified UI for all of them, and ultimately replace the top-right-corner login links.

Phase 2

Once we have each individual credential type working independently, it becomes a lot easier to unify them into a single UI. We'd expect that much of that work would result in the development of immediate mediation and would allow us to arrive at the desired end state.

Alternatives Under Consideration

  • Should this be only available for agentic browsers?
    • The intuition is that we shouldn't design markup that is only available to agentic browsing because it tends to be hard to develop again and maintain.
  • Can/should developers be able to control whether the <login> element is a "semantics only" element (such as <search>) so that it can be deployed exclusively in agentic browsers (but not affect regular users?)? If so, how?

Should <login> have default rendering?

<geolocation> and <install> have a "default rendering" and "controlled" rendering which raises some user comprehension bars. We should consider if that would be applicable to <login>.

Should <login> be like a <select>?

This open question is similar to the previous/next one, but has to do with the desire to make <login> both (a) have a rendering semantic and (b) participate in forms, and the most common analogy is to make <login> work like a <select> and <credential> work like an <option> that contributes to the container.

A browser could render <login> like a visually styled <select> (e.g. maybe it is a login icon, rather than a dropbox) and allows the user to choose one between many of the available login options.

One of the challenges that occurred as we thought this through was rendering private credential information inline and breaking contextual integrity: displaying cross-site information inline.

Still, we think there is something useful/desirable to think of <login> as a <select> element, so worth noting that this is under consideration.

Should <login> participate in <form> so that it can be used declaratively?

All forms of credentials are most useful server-side rather than client-side, so it would be nice to see them be able to participate in <form>s. For example, something along the lines of:

<form action="server.php" method="POST">
  <login name="token">
    <credential type="publickey" challenge="1234" rpId="example.com" userVerification="preferred"></credential>
    <credential type="federated" clientId="1234" configURL="https://idp1.example/config"></credential>
    <credential type="federated" clientId="5678" configURL="https://idp2.example/config"></credential>
  </login>
</form>

Alternatives Considered

Semantics-only markup

We considered a series of alternatives that were "sematics only" (e.g. markup that doesn't have any effect in the rendering engine), such as microdata and JSON-LD.

We found this limitation to be less useful because it could lead to markup being poorly maintained over time if it was intended only for agentic browsers.

<script type="federation">

<script type="federation">
{
  clientID: "1234",
  configURL: "https://idp.example",
}
</script>
<script>
document.addEventListener("login", () => ...)
</script>

ARIA role="login"

This is a variation to augument role with an additional landmak, login, akin to search:

<span role="login">
  <!-- how would we encode the rest of the FedCM parameters in the ARIA parameters? maybe that's not right? -->
  Sign-in with X
</span>

Open questions:

  • How would we encode the FedCM parameters in ARIA?
  • How do we throw a javascript event to return the result?
  • What should be the ARIA role that the "login" role should have? Should it be a landmark?
  • How do we handle non-conforming screen readers? How do we make it backwards compatible to unchanged screen readers?

Microdata

This proposal is to introduce to LoginAction a property called federation which describes what the FedCM request would be.

For example:

<div itemscope itemtype="https://schema.org/LoginAction">
  <data itemprop="federation" 
    value="client_id=\"1234\", config_url=\"https://idp.example/fedcm.json\"" />
  <button>Sign-in with X</button>
</div>

Open Questions:

  • See open questions about ARIA above

JSON-LD

This proposal is to introduce to LoginAction a property called federation which describes what the FedCM request would be.

For example:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "LoginAction",
  "federation": {
    "providers": [{
      "configURL": "https://idp.example/config.json",
      "clientId": "1234",
      "nonce": "4567",
      "fields": ["email", "name", "picture"],
     }]
  },
}
</script>
<script>
document.addEventListener("login", () => ...)
</script>

Mediation: conditional

In this variation, we use the mediation="conditional" parameter to let the agent operate in the unresolved promise.

const {token} = await navigator.credentials.get({
  mediation: "conditional",
  identity: { /** ... params ... */ }
});

<permission type="login">

We could extend the PEPC element to introduce a type="login" parameter.

<permission type="login" federation="clientId='1234', configURL='https://idp.example/config.json'">
   <a href="https://idp.example/oauth?...">Sign-in with IdP</a>  
</permission>

meta tags

In this variation we’d use the tag disassociated with the element to be clicked.

<meta http-equiv="Federated-Authentication" 
  content="client_id=\"1234\", config_url=\"https://idp.example/fedcm.json\""
>
<script>
document.addEventListener("login", ({token}) => login(token));
</script>

Overload WWW-Authenticate

In this variation we’d support a declarative request made via HTTP headers, like WWW-Authenticate or introduce a few one:

WWW-Authenticate: Federated; client_id="1234", config_url="https://idp.example/fedcm.json"

Cons:

  • Requires RPs to redeploy their servers
  • WWW-Authenticate is blocking (and because of that, we think, poorly adopted)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published