├── .github └── workflows │ ├── build-idl.yaml │ └── build-validate-publish.yaml ├── .gitignore ├── .pr-preview.json ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── compile.sh ├── explorations ├── HOWTO-chrome.md ├── README.md ├── activation.md ├── alternatives_considered.md ├── cookies.md ├── debug-network-requests-chrome.md ├── directed_basic_profile.md ├── directed_identifiers.md ├── drafts │ ├── delegation_oriented_api.md │ └── mediation_oriented_api.md ├── glossary.md ├── iframe_support.md ├── navigations.md ├── permission_oriented_api.md ├── prior.md ├── problem.md ├── proposal.md ├── related_problems.md ├── roadmap.md └── static │ ├── anchor-js.min.js │ ├── delegation-api-flow.svg │ ├── delegation-api-recovery-legacy-flow.svg │ ├── delegation-api-recovery-signin-flow.svg │ ├── delegation-api-signup-flow.svg │ ├── droid.css │ ├── favicon.ico │ ├── google-sans.css │ ├── idp.html │ ├── index.css │ ├── mock1.svg │ ├── mock10.svg │ ├── mock11.svg │ ├── mock12.svg │ ├── mock14.svg │ ├── mock15.svg │ ├── mock16.svg │ ├── mock17.svg │ ├── mock18.svg │ ├── mock19.svg │ ├── mock2.svg │ ├── mock20.svg │ ├── mock21.svg │ ├── mock22.svg │ ├── mock24.svg │ ├── mock25.svg │ ├── mock26.svg │ ├── mock27.svg │ ├── mock28.svg │ ├── mock29.svg │ ├── mock30.svg │ ├── mock32.svg │ ├── mock33.svg │ ├── mock35.svg │ ├── mock36.svg │ ├── mock38.svg │ ├── mock39.gif │ ├── mock4.svg │ ├── mock40.gif │ ├── mock41.svg │ ├── mock44.svg │ ├── mock6.svg │ ├── mock7.svg │ ├── mock8.png │ ├── mock9.svg │ ├── net-export │ ├── fedcm-1.png │ ├── fedcm-2.png │ ├── net-export-entry.png │ ├── net-export-stop.png │ ├── netlog-viewer-entry.png │ └── netlog-viewer-example.png │ ├── permission_based_flow.svg │ ├── rouge.css │ └── rp.html ├── meetings ├── 2020 │ ├── Browsers and Federation - OpenID.pdf │ ├── The Web Platform, Privacy and Federation - IIW.pdf │ └── The Web Platform, Privacy and Federation - TPAC.pdf ├── 2021 │ ├── 2021-05-25-notes.md │ ├── 2021-05-26-notes.md │ ├── 2021.05.25 - Identity Workshop - Microsoft Edge.pdf │ ├── 25-26_May_2021.md │ ├── BlinkOn 15 -- FedCM.pdf │ ├── FedCM @ TPAC 2021 (1).pdf │ ├── FedCM_ The Timming Attack Problem (1).pdf │ ├── Federated Credential Management - TPAC 2021.pdf │ ├── Firefox and Federated Login.pdf │ ├── Intro - Federation and Browsers.pdf │ ├── Web Identity API.pdf │ ├── WebID - BlinkOn 14.pdf │ ├── WebID And the Privacy Sandbox.pdf │ ├── mozilla-screenshot-1.png │ ├── mozilla-screenshot-2.png │ ├── poll1.png │ ├── poll2.png │ ├── poll3.png │ ├── poll4.png │ └── poll5.png ├── 2022 │ ├── FedCM @ TPAC.pdf │ ├── FedCM BlinkOn 16.pdf │ ├── FedCM_ Options for the Timing Attack Problem (8_16_2022).pdf │ └── FedCM_ Options for the Timing Attack Problem 2022-08-31.pdf └── 2023 │ └── CHAPI-FedCM-CCG-Jan-2023.pdf ├── privacy_security_questionnaire.md ├── spec ├── Makefile ├── extract_idl.rb ├── img │ ├── mock13.svg │ ├── mock23.svg │ ├── mock3.svg │ ├── mock31.svg │ ├── mock34.svg │ ├── mock37.svg │ ├── mock42.svg │ ├── mock43.svg │ ├── mock45.svg │ ├── mock46.svg │ └── mock5.svg └── index.bs └── w3c.json /.github/workflows/build-idl.yaml: -------------------------------------------------------------------------------- 1 | name: Publish IDL to GitHub pages 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v2 14 | 15 | - name: Build 16 | run: | 17 | make -C spec idl 18 | mkdir out 19 | cp spec/fedcm.idl out/ 20 | 21 | - name: Deploy 22 | if: ${{ success() && github.ref == 'refs/heads/main' }} 23 | uses: JamesIves/github-pages-deploy-action@4.1.3 24 | with: 25 | BRANCH: gh-pages 26 | FOLDER: out 27 | CLEAN-EXCLUDE: 28 | index.html 29 | static 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/build-validate-publish.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | run: 9 | name: Build, Validate, and Publish 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: w3c/spec-prod@v2 14 | with: 15 | GH_PAGES_BRANCH: gh-pages 16 | BUILD_FAIL_ON: nothing 17 | SOURCE: spec/index.bs 18 | DESTINATION: index.html 19 | TOOLCHAIN: bikeshed 20 | VALIDATE_MARKUP: false 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | spec/index.html 2 | spec/fedcm.idl 3 | spec/login-status.html 4 | spec/login-status.idl 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "spec/index.bs", 3 | "type": "bikeshed", 4 | "params": { 5 | "force": 1 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Federated Identity Community Group 2 | 3 | This repository is being used for work in the W3C Federated Identity Community Group, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, 5 | you must join the CG. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request comment. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors under the 2 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 3 | 4 | Contributions to Specifications are made under the 5 | [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 6 | 7 | Contributions to Test Suites are made under the 8 | [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html) 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FedID CG Federated Credentials Management 2 | 3 | This is the repository for the W3C's FedID CG Federated Credentials Management API. 4 | 5 | Developer documentation: [Federated Credential Management (FedCM) API](https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API) 6 | 7 | Editor's draft of the spec [here](https://w3c-fedid.github.io/FedCM/) 8 | 9 | ## Introduction 10 | 11 | The Federated Credential Management (FedCM) API provides a modern, privacy-preserving 12 | standard for federated identity on the web. It enables a more secure and intuitive 13 | user experience for signing in to websites (Relying Parties) with accounts from a 14 | trusted Identity Provider, all through a browser-mediated and standardized flow. 15 | 16 | In an era of increasing focus on user privacy and data control, the FedCM API offers 17 | a forward-looking solution to the known privacy and usability challenges of 18 | traditional federated login systems. By introducing the browser as an active 19 | participant, it creates a more interoperable and consistent authentication process. 20 | This ensures that users have a clearer understanding and more explicit control over 21 | what information is being shared and with whom. 22 | 23 | For websites, FedCM offers a durable and efficient API for implementing 24 | federated sign-in that is not dependent on the shifting landscape of browser 25 | tracking technologies. It represents a proactive step towards building a more 26 | trustworthy and user-centric web by improving the fundamental mechanics of how 27 | we manage identity online. 28 | 29 | Identity providers gain increased visibility with FedCM. The API allows the 30 | browser to display a single account chooser that can include multiple providers, 31 | letting users easily select their favorite. This unified login experience, managed 32 | directly by the browser, opens up new access points for providers. 33 | 34 | The [documentation](https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API) 35 | and [spec](https://w3c-fedid.github.io/FedCM) provide a potential API and the 36 | rationale behind that API's design. 37 | 38 | ## Contributing 39 | 40 | There are several ways to contribute to the Federated Credential Management API. 41 | 42 | * If you'd like to try out the current demo of the FedCM API you can follow the 43 | [HOWTO](explorations/HOWTO-chrome.md) document. A Firefox implementation is on 44 | the works so stay tuned! 45 | 46 | * If you're an Identity Provider, there are two sides of the implementation that 47 | will be needed and any feedback on either side is appreciated. 48 | 49 | 1. The [Identity Provider API](https://w3c-fedid.github.io/FedCM/#idp-api) describes 50 | the manifest and API needed server side. 51 | 2. The [Browser API](https://w3c-fedid.github.io/FedCM/#browser-api) describes the JavaScript 52 | interface to FedCM which will need to be utilized. 53 | 54 | * If you're a Relying Party (i.e. website) and would like to test the changes out 55 | we'd appreciate feedback, you have a couple of options: 56 | 57 | 1. Use the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API) 58 | to setup a fake IDP which can serve the needed JavaScript. You can also review the demo 59 | provided by the HOWTO and take a look at the 60 | [Relying Party API](https://w3c-fedid.github.io/FedCM/#rp) to see what is needed on the 61 | RP side. 62 | 2. Try using an existing IDP which deploys FedCM. 63 | 64 | ## Code of Conduct 65 | 66 | This group operates under [W3C's Code of Conduct Policy](http://www.w3.org/Consortium/cepc/). 67 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make -C spec 4 | -------------------------------------------------------------------------------- /explorations/HOWTO-chrome.md: -------------------------------------------------------------------------------- 1 | # HOWTO 2 | 3 | This article explains how to try out FedCM in Google Chrome. 4 | 5 | We will do our best to keep these instructions up to date as protocol and API 6 | changes occur. It will subsequently roll into downstream channels, but with lag 7 | in functionality and bug fixes since this is under development. 8 | 9 | ## Available functionality 10 | 11 | As of December 2022, FedCM API is available by default on Chrome (versions 108+). 12 | See [here](https://developer.chrome.com/docs/privacy-sandbox/fedcm/#use-api) for 13 | a detailed guide on how to use the parts of the API that have been shipped! 14 | 15 | ## Testing the API 16 | 17 | Testing can be easier in Incognito mode, Guest mode or with single-use profiles 18 | if sign-up status persistence is not desired. 19 | 20 | At the moment the only way to reset the sign-up status is to clear browsing data on the Chrome profile. 21 | This can be done from the [ClearBrowsing Data (chrome://settings/clearBrowserData)] [Settings] dialog. 22 | Under [Advanced] select the [Site Settings] checkbox. Also be sure the time range of data being cleared 23 | includes the time when the sign-up status was set. 24 | 25 | ## Experimental functionality 26 | 27 | To test experimental functionality: 28 | 29 | 1. Download Google Chrome Canary. It is best to experiment with the latest 30 | build possible to get the most up-to-date implementation. 31 | 2. FedCM is blocked if third party cookies are blocked. Ensure the Chrome 32 | version you're using is not blocking third party cookies by navigating to 33 | `chrome://settings/cookies`. 34 | 3. Enable your experimental FedCM feature. This can be done directly from 35 | `chrome://flags` and searching 'fedcm' to see all available features. 36 | 37 | The list of experimental features can be found [here](/proposals/README.md). 38 | 39 | ### Logout 40 | 41 | We have been experimenting with methods for helping session management 42 | features continue to work that currently rely on third-party cookies. So far the 43 | only implemented proposal is an API for Logout. 44 | 45 | The Logout API, `IdentityCredential.logoutRPs()` which is being explored as a way 46 | to preserve OIDC front-channel logout and SAML Single Signout with loss of 47 | access to third-party cookies in embedded contexts. It is intended to replace 48 | situations where an IDP logging out a user also must log out the user in RP 49 | contexts and would normally do it using iframes with each RP's known logout URL. 50 | 51 | The API takes an array of URLs as an argument. For each URL, the browser 52 | determines if the user is known to have previously logged in to the RP using 53 | that IDP, and if it has, it sends a credentialed GET request to that URL. 54 | 55 | ```js 56 | IdentityCredential.logoutRPs([{ 57 | url: "https://rp1.example/logout", 58 | accountId: "123", 59 | }, { 60 | url: "https://rp2.example/logout", 61 | accountId: "456", 62 | }]); 63 | ``` 64 | 65 | For security reasons, the IDP does not learn whether any of the network requests 66 | succeeded or failed. 67 | 68 | ### LoginHint 69 | 70 | To use the LoginHint API: 71 | 72 | * Add an array of `hints` to the accounts described in the accounts endpoint: 73 | 74 | ``` 75 | { 76 | accounts: [{ 77 | id: "accountId", 78 | email: "account@email.com", 79 | hints: ["hint", "otherHint"], 80 | ... 81 | }, ...] 82 | } 83 | ``` 84 | 85 | * Invoke the API with the `loginHint` parameter like so: 86 | 87 | ```js 88 | return await navigator.credentials.get({ 89 | identity: { 90 | providers: [{ 91 | configURL: "https://idp.example/config.json", 92 | clientId: "123", 93 | nonce: nonce, 94 | loginHint : "hint" 95 | }] 96 | } 97 | }); 98 | ``` 99 | 100 | Now, only accounts with the "hint" provided will show in the chooser. 101 | 102 | ### UserInfo 103 | 104 | To use the UserInfo API: 105 | 106 | * The RP must embed an IDP iframe, which will perform the query. 107 | * The embedded iframe must receive permissions to invoke FedCM (via Permissions Policy). 108 | * The user first needs to go through the FedCM flow once before invoking UserInfo. 109 | * In a subsequent site visit, the IDP iframe may invoke UserInfo: 110 | 111 | ```js 112 | const user_info = await IdentityProvider.getUserInfo({ 113 | configUrl: "https://idp.example/config.json", 114 | clientId: "client1234" 115 | }); 116 | 117 | user_info.forEach( info => { 118 | // It's up to the IDP regarding how to display the returned accounts. 119 | // Accounts are sorted based on RP registration status. 120 | const name = info.name; 121 | const given_name = info.given_name; 122 | const picture = info.picture; 123 | const email = info.email; 124 | } 125 | ``` 126 | 127 | ### RP Context 128 | 129 | To use the RP Context API: 130 | 131 | * Provide the `context` value in JS, like so: 132 | 133 | ```js 134 | const {token} = await navigator.credentials.get({ 135 | identity: { 136 | context: "signup", 137 | providers: [{ 138 | configURL: "https://idp.example/fedcm.json", 139 | clientId: "1234", 140 | }], 141 | } 142 | }); 143 | ``` 144 | 145 | Now, the browser UI will be different based on the value provided. 146 | 147 | ### IdP Sign-in Status API 148 | 149 | To use the IdP Sign-in Status API: 150 | 151 | 1. Enable the experimental feature `FedCM with FedCM IDP sign-in status` in `chrome://flags`. 152 | 2. When the user logs-in to the IdP, use the following HTTP header `IdP-SignIn-Status: action=signin`. 153 | 3. When the user logs-out of all of their accounts in the IdP, use the following HTTP header `IdP-SignIn-Status: action=signed-out`. 154 | 4. Add a `signin_url": "/idp_login.html` property to the `configURL` configuration. 155 | 5. The browser is going load the `signin_url` when the user is signed-out of the IdP. 156 | 6. Call `IdentityProvider.close()` when the user is done logging-in to the IdP. 157 | 158 | ### Error API 159 | 160 | To use the Error API: 161 | 162 | * Enable the experimental feature `FedCmError` in `chrome://flags`. 163 | * Provide an `error` in the ID assertion endpoint instead of a `token`: 164 | ``` 165 | { 166 | "error" : { 167 | "code" : "access_denied", 168 | "url" : "https://idp.example/error?type=foo" 169 | } 170 | } 171 | ``` 172 | Note that the `error` field in the response including both `code` and `url` is 173 | optional. As long as the flag is enabled, Chrome will render an error UI when 174 | the token request fails. The `error` field is used to customize the flow when an 175 | error happens. Chrome will show a customized UI with proper error message if the 176 | code is "invalid_request", "unauthorized_client", "access_denied", "server_error", 177 | or "temporarily_unavailable". If a `url` field is provided and same-site with 178 | the IdP's `configURL`, Chrome will add an affordance for users to open a new 179 | page (e.g., via pop-up window) with that URL to learn more about the error on 180 | that page. 181 | 182 | ### Auto-selected Flag API 183 | 184 | To use the Auto-selected Flag API: 185 | * Enable the experimental feature `FedCmAutoSelectedFlag` in `chrome://flags`. 186 | 187 | The browser will send a new boolean to represent whether auto re-authentication 188 | was triggered such that the account was auto selected by the browser in the flow 189 | to both the IdP and the API caller. 190 | 191 | For IdP, the browser will include `is_auto_selected` in the request sent to the 192 | ID assersion endpoint: 193 | ``` 194 | POST /fedcm_assertion_endpoint HTTP/1.1 195 | Host: idp.example 196 | Origin: https://rp.example/ 197 | Content-Type: application/x-www-form-urlencoded 198 | Cookie: 0x23223 199 | Sec-Fetch-Dest: webidentity 200 | 201 | account_id=123&client_id=client1234&nonce=Ct60bD&disclosure_text_shown=true&is_auto_selected=true 202 | ``` 203 | 204 | For the API caller, the browser will include a boolean when resolving the 205 | promise: 206 | ``` 207 | const cred = await navigator.credentials.get({ 208 | identity: { 209 | providers: [{ 210 | configURL: "https://idp.example/manifest.json", 211 | clientId: "1234" 212 | }] 213 | } 214 | }); 215 | 216 | const token = cred.token; 217 | if (cred.isAutoSelected !== undefined) { 218 | const isAutoSelected = cred.isAutoSelected; 219 | } 220 | ``` 221 | 222 | ### DomainHint 223 | 224 | To use the DomainHint: 225 | * Ensure that chrome://version shows 121.0.6146.0 or higher. 226 | * Enable the experimental feature `FedCmDomainHint` in `chrome://flags`. 227 | 228 | * Add an array of `domain_hints` to the accounts described in the accounts endpoint: 229 | 230 | ``` 231 | { 232 | accounts: [{ 233 | id: "karenCorp1", 234 | email: "karen@corp1.com", 235 | name: "Karen", 236 | domain_hints: ["corp1", "corp2"], 237 | }, { 238 | id: "otherId", 239 | email: "karen@mail.com", 240 | name: "Karen", 241 | }, { 242 | id: "karenCorp3", 243 | email: "karen@corp3.com, 244 | name: "Karen", 245 | domain_hints: ["corp3"], 246 | } 247 | }, ...] 248 | } 249 | ``` 250 | 251 | * Invoke the API with the `domainHint` parameter like so: 252 | 253 | ```js 254 | // This will show the karenCorp1 account. 255 | return await navigator.credentials.get({ 256 | identity: { 257 | providers: [{ 258 | configURL: "https://idp.example/config.json", 259 | clientId: "123", 260 | nonce: nonce, 261 | domainHint : "corp1" 262 | }] 263 | } 264 | }); 265 | ``` 266 | 267 | Now, only accounts matching the hint provided will show in the chooser. 268 | 269 | You may also use "any" to show only accounts which list at least one domain hint. 270 | 271 | ```js 272 | // This will show the karenCorp1 and karenCorp3 accounts. 273 | return await navigator.credentials.get({ 274 | identity: { 275 | providers: [{ 276 | configURL: "https://idp.example/config.json", 277 | clientId: "123", 278 | nonce: nonce, 279 | domainHint : "any" 280 | }] 281 | } 282 | }); 283 | ``` 284 | 285 | ### Disconnect API 286 | 287 | To use the Disconnect API: 288 | * Ensure that chrome://version shows 121.0.6145.0 or higher. 289 | * Enable the experimental feature `FedCmDisconnect` in `chrome://flags`. 290 | 291 | Add a disconnect endpoint to the FedCM config file. It must be same-origin 292 | with the config file. 293 | 294 | ```json 295 | { 296 | "accounts_endpoint": "/accounts", 297 | "id_assertion_endpoint": "/assertion", 298 | ... 299 | "disconnect_endpoint": "/disconnect" 300 | } 301 | ``` 302 | 303 | Implement the `disconnect_endpoint`. It is fetched using a POST credentialed 304 | request with CORS mode: 305 | 306 | ``` 307 | POST /disconnect HTTP/1.1 308 | Host: idp.example 309 | Referer: rp.example 310 | Content-Type: application/x-www-form-urlencoded 311 | Cookie: 0x123 312 | Sec-Fetch-Dest: webidentity 313 | 314 | account_hint=account456&client_id=rp123 315 | ``` 316 | 317 | The IdP can then disconnect the account and respond with the 318 | `Access-Control-Allow-Origin` and `Access-Control-Allow-Credentials` headers to 319 | satisfy CORS, and in the body of the response it should include a JSON with the 320 | account ID of the account that has been disconnected. 321 | 322 | ```json 323 | { 324 | "account_id": "account456Id" 325 | } 326 | ``` 327 | 328 | When a user goes through the FedCM flow, the browser stores that (RP, IDP, account) 329 | knowledge in browser storage in order to allow auto reauthn and User Info API to 330 | work correctly in the future. If the browser finds an account in local storage 331 | matching the ID provided, it will note the disconnection of that account. If the 332 | IdP fails by either returning some network error or saying that the disconnection 333 | was unsuccessful, or if the `account_id` is nowhere to be found, the browser will 334 | remove from local storage all of the federated accounts associated with the (RP, 335 | IDP). 336 | 337 | ### Button Flow 338 | The button flow differs from the widget flow in several ways. The most significant 339 | difference is that the button flow requires a user gesture such as clicking on a 340 | sign-in button. This means that a user must be able to successfully sign in with a 341 | federated account using this flow. In contrast, the widget flow is an optimized 342 | flow that can reduce sign-in friction. This means that if the widget flow is 343 | unavailable, a user can still click a "Sign in with IdP" button to continue. See 344 | illustrative [mocks here](https://docs.google.com/presentation/d/1iURrPakaHgBfQ6mAefKijjxToiTTgBSPz1rtaV0od98/edit?usp=sharing). 345 | 346 | #### Button Mode API 347 | To use the Button Mode API: 348 | * Enable the experimental feature `FedCmButtonMode` in `chrome://flags`. 349 | * Make sure to invoke the API behind [transient user activation](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation). 350 | * Invoke the API with the `mode` parameter like so: 351 | ```js 352 | return await navigator.credentials.get({ 353 | identity: { 354 | providers: [{ 355 | configURL: "https://idp.example/config.json", 356 | clientId: "123", 357 | nonce: nonce 358 | }], 359 | mode: "button" 360 | } 361 | }); 362 | ``` 363 | 364 | The browser will send a new parameter to the IdP representing the request type by including 365 | `mode=button` in the request sent to the ID assersion endpoint: 366 | ``` 367 | POST /fedcm_assertion_endpoint HTTP/1.1 368 | Host: idp.example 369 | Origin: https://rp.example/ 370 | Content-Type: application/x-www-form-urlencoded 371 | Cookie: 0x23223 372 | Sec-Fetch-Dest: webidentity 373 | 374 | account_id=123&client_id=client1234&nonce=Ct60bD&disclosure_text_shown=true&is_auto_selected=false 375 | &mode=button 376 | ``` 377 | Note that we currently only include the new parameter in the button flow. Other flow 378 | types such as "widget" (name TBD) will be added when Chrome ships this feature. 379 | 380 | #### Use Other Account API 381 | This API allows users to use other accounts in the account chooser when, for example, IdPs 382 | support multiple accounts or replacing the existing account. 383 | 384 | To use the Use Other Account API: 385 | * Enable the experimental feature `FedCmUseOtherAccount` in `chrome://flags`. 386 | * IdP specifies the following in the FedCM config file: 387 | ``` 388 | { 389 | "accounts_endpoint" : ..., 390 | "modes: { 391 | "button": { 392 | "supports_use_other_account": true|false, 393 | } 394 | } 395 | } 396 | ``` 397 | 398 | ### Continuation API 399 | This API lets the IdP request that the authorization flow should continue 400 | in a popup window that is controlled by the IdP. This can be used to request 401 | additional permission, to ask a user to confirm their account details, or 402 | for a variety of other use cases. 403 | 404 | To use this feature: 405 | * Enable the experimental feature `FedCmAuthz` in chrome://flags 406 | * Return a "continue_on" field with a URL instead of a token 407 | from the ID assertion endpoint. For example: 408 | ```js 409 | { 410 | "continue_on": "https://idp.example/finish_login?account_id=123" 411 | } 412 | ``` 413 | * When the authorization flow finishes, call `IdentityProvider.resolve` to close the 414 | popup and provide the token that will be passed to the RP: 415 | ```js 416 | IdentityProvider.resolve("this is the token"); 417 | ``` 418 | * If the account ID has changed (for example, if the popup provided a "Switch 419 | User" function), you can specify it in a second parameter: 420 | ```js 421 | IdentityProvider.resolve("this is the token", {accountId: "123"}); 422 | ``` 423 | * If the user cancels the login flow, call `IdentityProvider.close` to close 424 | the popup and reject the promise that was returned from `navigator.credentials.get`: 425 | ```js 426 | IdentityProvider.close(); 427 | ``` 428 | 429 | ### Parameters API 430 | This feature lets RPs specify additional key/value pairs that will get sent 431 | to the ID assertion endpoint. 432 | 433 | To use this feature: 434 | * Enable the experimental feature `FedCmAuthz` in chrome://flags 435 | * Add a `params` field to the `navigator.credentials.get` call: 436 | ```js 437 | navigator.credentials.get({ 438 | identity: { 439 | providers: [{ 440 | configURL: "https://idp.example/config.json", 441 | clientId: "123", 442 | nonce: nonce, 443 | params: { 444 | "key": "value", 445 | "anything_goes": "yes", 446 | "really": "yes", 447 | "scopes": "calendar.readonly", 448 | "dpop": "something", 449 | "moar": "sure", 450 | } 451 | }], 452 | } 453 | }); 454 | ``` 455 | * These key/value pairs will be sent as-is in the ID assertion request: 456 | `account_id=123&key=value&anything_goes=yes&really=yes&scopes=calendar.readonly&dpop=something&moar=sure&...` 457 | 458 | 459 | ### Multiple configURLs 460 | This feature lets you have multiple different config files under the same 461 | eTLD+1 as long as they all have the same accounts_endpoint. This can be 462 | useful to specify different branding or different ID assertion endpoints. 463 | 464 | To use this feature: 465 | * Enable the experimental feature `FedCmAuthz` in chrome://flags 466 | * Add the login_url and accounts_endpoint to the .well-known/web-identity 467 | file: 468 | ```js 469 | { 470 | "provider_urls": [ 471 | // keep this unchanged 472 | ], 473 | "accounts_endpoint": "https://fedcm.idp.example/accounts", 474 | "login_url": "https://fedcm.idp.example/login.html" 475 | } 476 | ``` 477 | 478 | ### Account labels 479 | The account labels API lets IdPs give a list of labels to an account and 480 | lets different config files specify a filter for those labels. 481 | 482 | To use the API: 483 | * Enable the experimental feature `FedCmAuthz` in chrome://flags 484 | * Add a `labels` field to accounts in the account endpoint: 485 | ```js 486 | { 487 | "name": "John Smith", 488 | //... 489 | "labels": ["label1"] 490 | } 491 | ``` 492 | * Add the desired label to the config file: 493 | ```js 494 | { 495 | "accounts_endpoint": "...", 496 | // ... 497 | "accounts": { 498 | "include": "label1" 499 | } 500 | } 501 | ``` 502 | -------------------------------------------------------------------------------- /explorations/README.md: -------------------------------------------------------------------------------- 1 | # Federated Credentials Management 2 | 3 | FedCM is an **active** exploration into how to evolve the web as a result 4 | of the **ongoing** privacy-oriented changes in browsers (e.g. 5 | [1](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/), 6 | [2](https://blog.mozilla.org/blog/2019/09/03/todays-firefox-blocks-third-party-tracking-cookies-and-cryptomining-by-default/) 7 | and [3](https://blog.google/products/chrome/privacy-sustainability-and-the-importance-of-and/)). 8 | FedCM attempts to **preserve** and **elevate** identity federation (e.g. OpenID, 9 | OAuth and SAML) for a more private Web. 10 | 11 | In order to start understanding the landscape of federation, we've started an 12 | active exploration into the problem space, potential end states, and possible 13 | solutions. These all serve the purpose of providing context, understanding and 14 | a shared idea of where we _could_ go. For a more specific document on what can 15 | be done right now, please see the 16 | [Federated Credential Management API](https://w3c-fedid.github.io/FedCM) proposal. 17 | 18 | This exploration has been broken into several sections. 19 | 20 | 1. What is the [language](glossary.md) being used? 21 | 1. What's the [problem](problem.md) being solved? 22 | * What are some [related problems](related_problems.md)? 23 | * What has been tried [previously](prior.md)? 24 | 1. Description of where we [should](proposal.md) be and accompanying 25 | [FedCM API](https://w3c-fedid.github.io/FedCM) proposal. 26 | * What [alternatives](alternatives_considered.md) have been explored? 27 | 1. Potential [roadmap](roadmap.md) to the [proposal](proposal.md). 28 | 29 | If you'd like to contribute, see the top-level [README](../README.md) for 30 | details. 31 | 32 | -------------------------------------------------------------------------------- /explorations/activation.md: -------------------------------------------------------------------------------- 1 | # Topology 2 | 3 | Currently, for **consumers**, sign-in flows on websites begin with a login screen that provides the user options to use federated identity, as illustrated in the mock below. Today, clicking the button for an IDP relies on general purpose primitives (typically [redirects or popups](#low-level)) to an IDP sign-in flow. 4 | 5 | ![](static/mock1.svg) 6 | 7 | There is a wide set of privacy and usability goals for identity sharing on the web, but early on we ran into better understanding the structural deployment of federation on the web, specifically the properties that make different activation/adoption strategies more or less plausible. 8 | 9 | For example, it is clear that there are relatively few public [IDPs](#idp) in use (say, tens), particularly in comparison to the number of [RPs](#rp) (say, millions) and their users (say, billions). A structural change that only requires adoption by IDPs and no changes or engagement on the part of RPs and users is significantly easier compared to redeploying millions of RPs or retraining billions of users. 10 | 11 | Fortunately, in more cases than not (by our estimates, about half of the deployment), RPs implement federated identity importing a script provided by - and under the control of - IDPs, giving us a major deployment vehicle: IDP SDKs loaded into RPs. 12 | 13 | ![](static/mock7.svg) 14 | 15 | Nonetheless, while much of the client-side code is under the (few) IDPs to control (e.g. we can replace redirects by other means), all of the server-side code is under the (many) RPs to control, meaning that that is significantly harder to change (say, years). The cases where RPs implement federated identity without a dynamically loaded SDK will have a longer deployment window and will be discussed separately. 16 | 17 | Likewise, changing user behavior and norms is hard because of the number of people involved (say, billions). Unfamiliar login flows could result in users declining to use federated options, and instead opting for username/password credentials during RP account creation. To address that, this proposal aims to provide an experience that minimizes the divergence from existing federated identity user experience as much it possibly can (e.g. introducing new user decisions to be made). 18 | 19 | So, with this deployment constraint in mind, let's look at some alternatives under exploration. 20 | -------------------------------------------------------------------------------- /explorations/alternatives_considered.md: -------------------------------------------------------------------------------- 1 | # Alternatives Considered 2 | 3 | Now that we have a deep understanding of (a) the [problem](README.md) and (b) the [motivations](https://w3c-fedid.github.io/FedCM/#privacy) and [topology](activation.md) of the parties involved, lets look at some **why not**s. 4 | 5 | ## The Status Quo 6 | 7 | A trivial alternative that is worth noting as a baseline is to "do nothing" and keep federation using low-level primitives like redirects and popups. 8 | 9 | That seemed clear to reject based on: 10 | 11 | - the inability to prevent the [RP tracking problem](glossary.md#rp-tracking) 12 | - the increasing constraints that are being put in place for cross-site communication through third-party cookies, postMessage and URL parameters as link decorations as a result of the [IDP tracking problem](glossary.md#idp-tracking) 13 | 14 | From here, the next incremental step we could look at is the [requestStorageAccess](https://developer.mozilla.org/en-US/docs/Web/API/Document/requestStorageAccess) API. 15 | 16 | ## The RequestStorageAccess API 17 | 18 | The [Document.requestStorageAccess()](https://developer.mozilla.org/en-US/docs/Web/API/Document/requestStorageAccess) API grants first-party storage to cross-origin subframes. In conjunction with iframes, an IDP could expose its service via cross-site postMessage communication once first-party storage has been granted. 19 | 20 | This approach has a couple of downsides: 21 | 22 | - the inability to prevent the [RP tracking problem](glossary.md#rp-tracking) 23 | - the general-purpose nature of the API leads to a lowest-common-denominator policy (e.g. a permission prompt that warns users of the worst case scenario) 24 | 25 | From here, let's try to break down the problem into smaller parts. 26 | -------------------------------------------------------------------------------- /explorations/cookies.md: -------------------------------------------------------------------------------- 1 | # Cookies 2 | 3 | This is a **proposal** for a high level API to support identity federation under this [threat model](https://w3c-fedid.github.io/FedCM/#privacy). 4 | 5 | It is widely known that browsers are either **already** blocking third party cookies or are planning to. 6 | 7 | > Publicly announced browser positions on third party cookies: 8 | > 9 | > 1. [Safari](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/): third party cookies are **already** blocked by **default** 10 | > 1. [Firefox](https://blog.mozilla.org/blog/2019/09/03/todays-firefox-blocks-third-party-tracking-cookies-and-cryptomining-by-default/): third party cookies are **already** blocked **by a blocklist**, and 11 | > 1. [Chrome](https://blog.google/products/chrome/privacy-sustainability-and-the-importance-of-and/): on iOS **already** blocked **by default** and intends to offer **alternatives** to make them **obsolete** in the [near term](https://www.blog.google/products/chrome/building-a-more-private-web/) in other platforms. 12 | 13 | Unfortunately, that has either broken or is about to break a few use cases in federation, namely [logging out](https://openid.net/specs/openid-connect-rpinitiated-1_0.html), [social buttons](https://developers.facebook.com/docs/facebook-login/userexperience/) and [widget personalization](https://developers.google.com/identity/one-tap/web). 14 | 15 | This is a proposal to preserve these operations in the absence of third party cookies. 16 | 17 | ## The lifecycle 18 | 19 | Cross-site communication is used throughout the entire lifecycle of the user signing in to a RP with an IDP, beginning at signing-up a new user all the way through managing the sessions (e.g. signing in, signing out or renewing refresh tokens). 20 | 21 | From a [privacy threat model](https://w3c-fedid.github.io/FedCM/#privacy) perspective, the design of this proposal is anchored on the observation that the most critical moment is when the identities between the RP and the IDP are joined for the very first time, namely when the user creates a new account in the RP using the identifiers from the IDP or when a user signs-in to an RP with an IDP for the first time in the browser: once the identities are joined, any arbitrary/uncontrolled cross-side communication can happen (with or without the browser's permission, e.g. via backchannel or cookie-less requests). 22 | 23 | In this proposal, the browser: 24 | 25 | 1. Intermediates (e.g. gathers the user consent / intent) to observe the moment in which the identities get joined for the very first time between RPs and IDPs (a sign-up or a sign-in) 26 | 1. Stores locally the relationship between the RP/IDP that was established 27 | 1. Based on the status of that relationship (which can be explicitly revoked, e.g. via API calls or user settings), unlocks third party cookies to be sent under controlled circumstances (e.g. signing-in, signing-out and renewing refresh tokens) 28 | 29 | The browser stores the state in which the user is at in the following state machine: 30 | 31 | ![](../spec/img/mock42.svg) 32 | 33 | Because the first moment in which the identies are joined is the most important/critical one, we'll start there. But then, assuming that the browser was able to observe that moment, we'll go over the APIs that it unlocks to support managing sessions: 34 | 35 | - [Account Management API](#account-management-api) 36 | - [Session Management API](#session-management-api) 37 | 38 | # Account Management API 39 | 40 | The goal of the account management API is for the user agent to intermediate the creation and revocation of user accounts in relying parties provisioned by identity providers. 41 | 42 | The account management API turns (unregistered) users into (registered) accounts (and vice-versa), which is in and of itself useful (e.g. providing simple authentication), but it also unlocks the more advanced [session management](#session-management-api) capabilities. 43 | 44 | In its most basic formulation, the RP invokes the sign-up process via a JS API (or alternatively via the [implicit invocation](#implicit-invocation) API), namely as an extension of the [CredentialManagement API](https://w3c.github.io/webappsec-credential-management). 45 | 46 | We propose to extend the [FederatedCredentialRequestOptions](https://w3c.github.io/webappsec-credential-management/#dictdef-federatedcredentialrequestoptions) and the [FederatedCredential](https://w3c.github.io/webappsec-credential-management/#federatedcredential) interface with the following properties: 47 | 48 | ```javascript 49 | dictionary FederatedIdentityProvider { 50 | required USVString url; 51 | USVString clientId; 52 | USVString nonce; 53 | }; 54 | 55 | partial dictionary FederatedCredentialRequestOptions { 56 | sequence<(DOMString or FederatedIdentityProvider)> providers; 57 | }; 58 | 59 | enum FederatedCredentialApprovedBy { 60 | "auto", 61 | "user" 62 | }; 63 | 64 | dictionary FederatedCredentialLogoutRequest { 65 | required USVString endpoint; 66 | required USVString accountId; 67 | }; 68 | 69 | [Exposed=Window, SecureContext] 70 | partial interface FederatedCredential : Credential { 71 | readonly attribute USVString idToken; 72 | readonly attribute FederatedCredentialApprovedBy approvedBy; 73 | 74 | static Promise revoke(USVString accountId); 75 | static Promise logout(optional sequence logout_requests = []); 76 | }; 77 | ``` 78 | 79 | With these extensions to the Credential Management API, here is an example of an invocation: 80 | 81 | ```javascript 82 | const {idtoken} = await navigator.credentials.get({ 83 | federated: { 84 | providers: [{ 85 | url: "https://accounts.example.com", 86 | clientId: "my_client_id", 87 | nonce: "abcxyz" 88 | }], 89 | }, 90 | }); 91 | ``` 92 | 93 | ## Sign-up 94 | 95 | An (unregistered) user turns into a (registered) account via a process we call sign-up. In this process, the user agent has never observed the association between the RP and the IDP, so it intermediates the registration process. 96 | 97 | The browser intercepts this invocation and runs the following algorithm for each RP/IDP pair: 98 | 99 | ![](../spec/img/mock43.svg) 100 | 101 | ### Fetch Well-Known 102 | 103 | As a convention, the browser expects a `application/json` file to be hosted on the `.well-known/fedcm` path of the `provider` host. 104 | 105 | The configuration file is expected to have the following format: 106 | 107 | | Property | Type | Method | Description | 108 | | --------------------- | ----------- | ------- | ----------------------------------------- | 109 | | accounts_endpoint | URL | GET | Returns a list of available user accounts | 110 | | client_id_metadata_endpoint | URL | GET | Returns RP metadata | 111 | | idtoken_endpoint | URL | POST | Returns a newly minted id token | 112 | | revocation_endpoint | URL | POST | Notifies IDP user deleted RP account | 113 | 114 | 115 | ### Fetch Accounts 116 | 117 | The `accounts_endpoint` is used to fetch a list of user's accounts. The fetch contains two important headers: 118 | 119 | 1. A `Sec-FedCM-CSRF` which can be used by the server to know that it is a FedCM request 120 | 1. The `Cookie` header which contains the IDP's cookie, allowing the IDP to restore the user's session 121 | 122 | The browser expects the response to have the following format: 123 | 124 | | Property | Type | Description | 125 | | --------------------- | ----------- | ---------------------------------------------------- | 126 | | accounts | Account[] | The list of user accounts available | 127 | 128 | 129 | Each `Account` type is an object with the following properties: 130 | 131 | | Property | Type | Description | 132 | | ------------ | ----------- | ----------------------------------------- | 133 | | account_id | String | The user's id | 134 | | name | String | The user's full name | 135 | | given_name | String | The user's given name | 136 | | email | String | The user's email address | 137 | | picture | URL | The user's profile picture | 138 | 139 | For example: 140 | 141 | ```http 142 | GET /accounts.php HTTP/1.1 143 | Host: idp.example 144 | Content-Type: application/json 145 | Cookie: 0x23223 146 | Sec-FedCM-CSRF: ?1 147 | ``` 148 | 149 | And here is an example of a typical response: 150 | 151 | ```http 152 | HTTP/1.1 200 OK 153 | Content-Type: application/json 154 | 155 | { 156 | "accounts": [{ 157 | "account_id": 1234, 158 | "name": "Sam Goto", 159 | "given_name": "Sam", 160 | "email": "samuelgoto@gmail.com", 161 | "picture": "https://accounts.idp.com/profile/123", 162 | }] 163 | } 164 | ``` 165 | 166 | ### Show Account Chooser 167 | 168 | With the accounts retrieved, the browser then controls the experience with the user to carry on: 169 | 170 | ![](static/mock44.svg) 171 | 172 | When the user selects an account, the browser calls the `idtoken_endpoint` to [create an IdToken](#create-idtoken). 173 | 174 | 175 | ### Create IdToken 176 | 177 | To create an idtoken, the browser issues a `POST` request to the `idtoken_endpoint`. 178 | 179 | The fetch contains two important headers: 180 | 181 | 1. A `Sec-FedCM-CSRF` which can be used by the server to know that it is a FedCM request 182 | 1. The `Cookie` header which contains the IDP's cookie, allowing the IDP to restore the user's session 183 | 184 | The request should include a JSON body with the following parameters. 185 | 186 | | Property | Type | Description | 187 | | ------------ | ----------- | ----------------------------------------- | 188 | | account_id | String | The account id that was selected | 189 | | request | Request | The request parameters | 190 | 191 | The `Request` object contains information about the relying party that is needed to mint an IdToken: 192 | 193 | | Property | Type | Description | 194 | | ------------ | ----------- | ----------------------------------------- | 195 | | client_id | String | The relying party's client id | 196 | | nonce | String | The nonce passed from the JS call | 197 | 198 | The response of the `POST` request is expected to have the following layout: 199 | 200 | | Property | Type | Description | 201 | | ------------ | ----------- | ----------------------------------------- | 202 | | id_token | String | The newly minted JWT | 203 | 204 | Here is an example of the `POST` request: 205 | 206 | ```http 207 | POST /fedcm/idtoken.php HTTP/1.1 208 | Host: idp.example 209 | Cookie: 123 210 | Sec-FedCM-CSRF: ?1 211 | Content-Type: application/json 212 | 213 | { 214 | "sub": "1234", 215 | "request": { 216 | "client_id" : "my_cliend_id", 217 | "scope": "openid email", 218 | "nonce": "abcxyz" 219 | } 220 | } 221 | ``` 222 | 223 | Which may result in the following response: 224 | 225 | ```json 226 | { 227 | "id_token" : "asdlkjop2awlasd" 228 | } 229 | ``` 230 | 231 | ### Show IDP Modal 232 | 233 | ## Unregistering 234 | 235 | > TODO(goto): write down how we are planning to address the revocation of accounts. 236 | > There are three formulations here (not mutually exclusive): 237 | > 238 | > - a user is able to revoke / unregister accounts in browser ui (e.g. settings page) 239 | > - the IDP is able to inform the browser when a revocation has happened 240 | > - maybe the RP gets to ask for unregistration too? 241 | 242 | 243 | # Session Management API 244 | 245 | ## Sign-in 246 | 247 | Signing-in is invoked precisely the same way as signing-up: 248 | 249 | For example: 250 | 251 | ```javascript 252 | const {idtoken} = await navigator.credentials.get({ 253 | federated: { 254 | providers: [{ 255 | url: "https://accounts.example.com", 256 | clientId: "my_client_id", 257 | nonce: "abcxyz" 258 | }], 259 | }, 260 | }); 261 | ``` 262 | 263 | The same algorithm used during [sign-up](#sign-up) is used, which falls back gracefully when the internal state of the browser already contains more than one registered account. 264 | 265 | 266 | ## Sign-out 267 | 268 | In enterprises, when users log out of IDPs, there is typically a desire for users to also be logged out of the RPs they signed into. This is typically accomplished by the IDPs loading iframes pointing to a pre-acquired endpoint for each of the relying parties ([details](https://www.identityserver.com/articles/the-challenge-of-building-saml-single-logout)). 269 | 270 | In this proposal, the browser exposes a new JS API that takes a list of endpoints as input and: 271 | 272 | 1. makes a credentialed fetch to all of the endpoints with a corresponding session. 273 | 1. clears the session associated with the current account. 274 | 275 | ```javascript 276 | await navigator.credentials.logout([ 277 | { 278 | endpoint: "https://rp1.com", 279 | accountId: "123" 280 | }, 281 | { 282 | endpoint: "https://rp2.com", 283 | accountId: "245" 284 | }, 285 | { 286 | endpoint: "https://rp3.com", 287 | accountId: "abc" 288 | } 289 | ]); 290 | ``` 291 | 292 | The logout endpoints are configured out-of-band in the process relying parties register with identity providers: the identity provider is the only entity aware of the endpoints that need to be loaded. So, an array of relying party logout endpoints is passed, and whenever the logouts have a coinciding observed login, a credentialed request is made: 293 | 294 | > NOTE(goto): the exact criteria to make the matching between the login and logout is TBD. two thoughts occurred to us: (a) matching origins and (b) making the IDP declare the endpoint upon login. 295 | 296 | ![](../spec/img/mock31.svg) 297 | 298 | 299 | # Alternatives under consideration 300 | 301 | ## Implicit invocation 302 | 303 | The implicit invocation flow is largely designed to support the deployment of FedCM without requiring relying parties to change. 304 | 305 | ## Sign-up 306 | 307 | ```javascript 308 | enum FederatedCredentialRequestOptionsMode { 309 | "mediated", 310 | "permission" 311 | }; 312 | 313 | dictionary FederatedCredentialRequestOptions { 314 | FederatedCredentialRequestOptionsMode mode = "permission"; 315 | }; 316 | ``` 317 | 318 | ## Sign-in 319 | 320 | ### fenced frames 321 | 322 | There is a variety of privacy controls that we are exploring, but the fenced frame variation is a good baseline. 323 | 324 | In this variation, we offer the user the identity-specific controls whenever cross-site identity-specific communication is conducted (e.g. from the relying party to the IDP and vice versa), based on exposing new high level identity-specific APIs. 325 | 326 | This is still under active exploration, but our efforts are going into exploring ways in which we can leverage [fenced frames](https://github.com/shivanigithub/fenced-frame) and introduce new high-level javascript APIs. 327 | 328 | For example, we are looking into ways we could replace the ` 38 | ``` 39 | 40 | And a developer may also choose to explicitly name all origins which should have access to the FedCM API via the HTTP response header. For instance, to fully disable the API on all origins, the developer could have the following HTTP header: 41 | 42 | ``` 43 | Permissions-Policy: identity-credentials-get=() 44 | ``` 45 | -------------------------------------------------------------------------------- /explorations/navigations.md: -------------------------------------------------------------------------------- 1 | # Navigations 2 | 3 | This is an **early exploration** of the design alternatives to address [bounce tracking](README.md#stage-2-bounce-tracking) under [this threat model](https://w3cping.github.io/privacy-threat-model/). 4 | 5 | This section goes over the **what** and the **how**. It presuposes that you have read and started from: 6 | 7 | - The **why**: the [problem statement](problem.md) and the [motivations](https://w3cping.github.io/privacy-threat-model/) and the [topology](activation.md) of the parties involved. 8 | - The **why not**: the [alternatives considered](alternatives_considered.md) (e.g. the [prior art](prior.md), the [status quo](alternatives_considered.md#the-status-quo) and the [requestStorageAccess API](alternatives_considered.md#the-request-storage-access-api)). 9 | 10 | We'll then go over the [high-level overview](#high-level-design) and a breakdown into two smaller problems: 11 | 12 | - [The Consumer API](#the-consumer-api) (i.e. the interface between the RP and the Browser) and 13 | - [The Provider API](#the-provider-api) (i.e. the interaction between the Browser and the IDP). 14 | 15 | In the first part of the last section will go over the (slightly less controversial) [Consumer API](#the-consumer-api) and the useful separation between: 16 | 17 | - The [Sign-in API](#the-sign-in-api) and 18 | - The [Authorization API](#the-authorization-api). 19 | 20 | Finally, we'll then enumerate a series of alternatives for the (much more contentious) [Provider API](#the-provider-api): 21 | 22 | - The [Permission-oriented](#the-permission-oriented-variation) Variation 23 | - The [Mediation-oriented](#the-mediation-oriented-variation) Variation 24 | - The [Delegation-oriented](#the-delegation-oriented-variation) Variation 25 | 26 | # High Level Design 27 | 28 | From a high level perspective, the browser acts as an mediator between two parties: the relying party and the identity provider. 29 | 30 | ![](static/mock14.svg) 31 | The browser exposes two distinct interfaces for the intermediation: 32 | 33 | - [The Consumer API](#the-consumer-api) to allow a relying party to request and receive an identity token and 34 | - [The Provider API](#the-provider-api) to allow an identity provider to provide an identity token 35 | 36 | We'll go over each of these separately next. 37 | 38 | # The Consumer API 39 | 40 | The consumer API is the Web Platform privacy-oriented API that relying parties call to request information from a specific identity provider, to be used in replacement of the current redirect/popup affordances that are currently used. 41 | 42 | From the perspective of [The Privacy Threat Model](https://w3cping.github.io/privacy-threat-model/), there are two notably distinct uses of federation: 43 | 44 | * [signing-in](glossary.md#federated-sign-in) and 45 | * [authorization](glossary.md#authorization) 46 | 47 | While both are implemented on top of OAuth as different scopes, the former (typically deployed with the `openid` oauth scope) captures a meaningful volume of usage (we estimate it be around 80% of the use) at a much more controlled surface area (including transactions done at the front channel with idtokens as opposed to access tokens), whereas the latter is much more powerful and used less frequently (as well as done primarily on the back channel). 48 | 49 | Lets first turn to the former use, and then go over authorization following that. 50 | 51 | ## The Sign-In API 52 | 53 | Simply put, the Sign-In API is a Web Platform affordance that takes an identity provider as input and returns a [directed basic profile](directed_basic_profile.md) as output. It substitutes the navigational/popup affordances currently used. 54 | 55 | We don't know yet exactly what it should look like, but here is an example to serve as a starting point: 56 | 57 | ```javascript 58 | // This is just a possible starting point, largely TBD. 59 | let {idToken} = await navigator.credentials.get({ 60 | provider: "https://accounts.example.com", 61 | // other OpenId connect parameters 62 | }); 63 | ``` 64 | 65 | Another notable alternative worth considering is a declarative API that would allow embedding the user experience inline in the content area while still keeping the cross-origin separation before user consent. For example: 66 | 67 | ```html 68 | 69 | ``` 70 | 71 | Upon invocation, the browser makes an assessment of the user's intention, for example making sure that the API was used as a result of a user gesture. 72 | 73 | From there, the browser proceeds to mediate the data exchange with the chose identity provider via [The Provider API](#the-provider-api). 74 | 75 | Upon success, the consumer API results into a [directed basic profile](directed_basic_profile.md). For example: 76 | 77 | ```json 78 | { 79 | "iss": "https://accounts.idp.com", 80 | "sub": "110169484474386276334", 81 | "aud": "https://example.com", 82 | "iat": "2342342", 83 | "name": "Sam G", 84 | "email": "sjkld2093@gmail.com", 85 | "email_verified": "true", 86 | "profile": "https://accounts.google.com/default-avatar.png", 87 | } 88 | ``` 89 | 90 | The [directed basic profile](directed_basic_profile.md) is signed into a JWT and then returned back to the relying party which can effectively get the user logged in. Here is [an example](https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmlkcC5jb20iLCJzdWIiOiIxMTAxNjk0ODQ0NzQzODYyNzYzMzQiLCJhdWQiOiJodHRwczovL2V4YW1wbGUuY29tIiwiaWF0IjoiMjM0MjM0MiIsIm5hbWUiOiJTYW0gRyIsImVtYWlsIjoic2prbGQyMDkzQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjoidHJ1ZSIsInByb2ZpbGUiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vZGVmYXVsdC1hdmF0YXIucG5nIn0.3fGpHH5IeL2fDxbToBLE2DWDf6hfHU5YfiSdfqRGlIA) of what a signed JWT looks like for the payload above. 91 | 92 | Another notable form of deployment of federation is over top level navigations. 93 | 94 | Because a significant part of federation is deployed over well-established protocols (e.g. OpenID, SAML), their HTTP profile is somewhat easy to spot. For example, for OpenID Connect requests/responses we could look at HTTP requests that have: 95 | 96 | - a **client_id** parameter 97 | - a **redirect_uri** parameter 98 | - a **scope** parameter 99 | - an accompanying **.well-known/openid-configuration** configuration 100 | 101 | Responses can be matched when they match: 102 | 103 | - a redirect to the previously used **redirect_uri** 104 | - an **id_token** parameter 105 | 106 | It is an active area of investigation to determine: 107 | 108 | 1. which and how many of these patterns we would want to use (too few and you over-classify, too many and you under-classify), 109 | 1. whether the same approach would work for other protocols (e.g. SAML). 110 | 1. whether we need an opt-in / explicit API and if so which (e.g. perhaps a special URL marker, like a reserved URL parameter or a scheme) 111 | 112 | ## The Authorization API 113 | 114 | Relying Parties often rely on more services from IDPs which are gathered via subsequent flows to get the user's authorization to release access to broader scopes. Notably, there is a long tail of these scopes, with little to no commonalities between them (say, access to calendar, photos, social graphs, etc). 115 | 116 | To allow users to continue accessing broader scopes, we expose a new API to mediate that flow. For example: 117 | 118 | ```javascript 119 | navigator.credentials.requestAuthorization({ 120 | scope: "https://idp.com/auth/calendar.readonly", 121 | provider: "https://idp.com", 122 | }); 123 | ``` 124 | 125 | Now that we looked at the surface area introduced for relying parties, lets turn into [The Provider API](#the-provider-api) and see what are the options under consideration for the intermediation between the user agent and the identity provider. 126 | 127 | # The Provider API 128 | 129 | The purpose of the Provider API is to fulfill the invocation of [The Consumer API](#the-Consumer-api) by coordinating with the identity provider. 130 | 131 | From the perspective of [The Privacy Threat Model](https://w3cping.github.io/privacy-threat-model/), the Provider API has a much wider set of choices and trade-offs: 132 | 133 | 1. Because of the [classification problem](README.md#the-classification-problem), we want to prevent a tracker from abusing this API by impersonating an IDP to track users. 134 | 1. Because of the [RP tracking problem](README.md#the-rp-tracking-problem), we want to promote directed identifiers as much as we can. 135 | 1. Because of the [IDP tracking problem](README.md#the-idp-tracking-problem), we want to keep IDPs involved only to the extent that they justifiably need to. 136 | 137 | We also want to make sure that: 138 | 139 | - There is a credible path towards eventual browser interoperability (e.g. firefox, safari, edge) 140 | - The scheme reaches an economically viable equilibrium for all parties involved, from a design of incentives perspective 141 | - The scheme handles gracefully federation on non-web platforms (e.g. Android, iOS, PlayStation, etc) 142 | - We minimize the deployment and activation windows (e.g. server-side / client-side and user-behavior backwards compatibility) for relying parties and identity providers 143 | - The scheme has a deliberate and well informed extensibility and ossification model, i.e. make extensible where innovation is constructive and ossify where there is less rapid iteration going on and there a direct value in terms of privacy/security. 144 | 145 | We believe we all still have a lot to learn from each other (browser vendors, identity providers, relying parties, etc) in choosing the mean between the extremes of excess and deficiency with regards to the trade-offs of privacy, usability and economic viability. 146 | 147 | Having said that, in the following section we'll enumerate some of the most prominent variations under consideration and their trade-offs. 148 | 149 | We'll try to go over the thought process and the biggest considerations to be made starting from the most basic thing that we could do to some of the most involved. 150 | 151 | The approaches are categorized into three general approaches: 152 | 153 | 1. The [Permission-oriented](#the-permission-oriented-variation) Variation 154 | 1. The [Mediation-oriented](#the-mediation-oriented-variation) Variation 155 | 1. The [Delegation-oriented](#the-delegation-oriented-variation) Variation 156 | 157 | ## The Permission-oriented Variation 158 | 159 | The simplest approach is to have FedCM offer APIs that allow cross-origin data sharing for sign-in and authorization use cases that works much as they do today, but with the user agents providing warnings and consent moments to the user when new tracking risks appear. 160 | 161 | ![](static/mock19.svg) 162 | 163 | An expanded exploration of this approach with its benefits and drawbacks can be seen [here](permission_oriented_api.md). 164 | 165 | Naturally, the next set of formulations try to address these two shortcomings at the cost of the autonomy of the IDP and the ossification of parts of the flow. 166 | 167 | ## The Mediation-oriented Variation 168 | 169 | In this formulation, the browser pulls the responsibility for itself to drive the profile exchange, enabling it to (a) bundle the consent moments described in the formulation above and (b) steer users to safer defaults. 170 | 171 | ![](static/mock15.svg) 172 | 173 | An expanded exploration of this approach with its benefits and drawbacks can be seen [here](mediation_oriented_api.md). 174 | 175 | ## The Delegation-oriented Variation 176 | 177 | The last alternative under consideration enables the user agent to finally address the [The IDP Tracking Problem](README.md#the-idp-tracking-problem) mechanically. 178 | 179 | In this formulation, the IDP delegates the presentation of identity assertions to the Browser. It accomplishes that by making the browser generate a public/private key pair and have the IDP sign a certificate attesting that the browser's private key can issue certificates for a certain JWT. 180 | 181 | The biggest benefits of this variation are: 182 | 183 | - The delegation mechanically solves the [The IDP Tracking Problem](README.md#the-idp-tracking-problem): it keeps the IDP unaware of where the user is signing-into while still enabling the user to recover its account while moving around. 184 | - Because there aren't any [IDP Tracking Problem](README.md#the-idp-tracking-problem) nor any [RP Tracking Problem](README.md#the-rp-tracking-problem), this can possibly be a zero-prompt, consequence-free UX. 185 | 186 | The biggest drawback of this variation is that it leads to a JWT that is not backwards compatible with the existing server-side deployment of relying parties (which are expecting the IDP to sign JTWs, not the Browser), which is O(K) hard to change. 187 | 188 | An expanded exploration of this approach with its benefits and drawbacks can be seen [here](https://docs.google.com/presentation/d/1Sym0k84omyL5Ls1lO6w4aGQ-s4EHrDzo8ZlheyzFOlw/edit#slide=id.ga40b1e6d4f_0_77). 189 | 190 | ## The Provider Authorization API 191 | 192 | The Provider Authorization API fulfills the request from the [Consumer Authorization API](#the-authorization-api). 193 | 194 | It is clearly not possible to enumerate all the various scopes that are in use, so it is clearer that: 195 | 196 | - the IDP needs to be involved in the authorization flow 197 | - the browser needs to apply the lowest common denominator policy (e.g. assume that the flow implies both the [IDP Tracking Problem](README.md#the-idp-tracking-problem) as well as the [RP Tracking Problem](README.md#the-rp-tracking-problem)) 198 | 199 | ![](static/mock20.svg) 200 | 201 | ## The Enterprise-oriented Variation 202 | 203 | To the best of our knowledge, we believe that business users (employees of a corporation) have a different set of privacy expectations compared to consumers, in that the accounts issued to employees are owned by the businesses (as opposed to the relationship a consumer has with social login providers). It is also clear to us too that the current deployment of businesses makes a non-trivial use of personal machines owned by employees, rather than machines that are issued by the business (which have a much easier ability to control enterprise policies). 204 | 205 | We believe that the controls should take that distinction into consideration, and that the biggest challenge is adversarial impersonation. 206 | 207 | ![](static/mock24.svg) 208 | 209 | This is still an active area of exploration, but to give a sense of direction, we are actively exploring making an abrupt separation between personal profiles and work profiles. The intuition here is that browser profiles are the closest delineation that can make a separation between personal use of your browser versus work use of your browser, along with the privacy expectations in each mode. 210 | 211 | ![](static/mock25.svg) 212 | 213 | In addition to the separation, and with the user's permission/control/understanding, it seems like it would be beneficial for business admins to have the ability to set work policies on a per-profile basis. 214 | -------------------------------------------------------------------------------- /explorations/permission_oriented_api.md: -------------------------------------------------------------------------------- 1 | # Permission-oriented API 2 | 3 | The philosophy underlying this approach is that browsers should be responsible for ensuring user awareness and permission for cross-site interactions that create tracking risk, and outside of that Relying Parties and Identity Providers should have maximal control of the user experience. 4 | 5 | # Permission flow properties 6 | 7 | ## Preventing IDP tracking 8 | The intention is to prevent [IDP tracking](glossary.md#idp-tracking) by requiring a user gesture on the RP's page before the API can be invoked, and by displaying an appropriate dialog to the user before any identifying user information can be passed from the RP to the IDP. Both of these restrictions can be relaxed if the user agent knows that the user has successfully completed a sign-in with this RP and IDP before. 9 | 10 | This flow contains an implicit assumption that 'global' information (including the RP’s origin) can be shared with the IDP based on a user gesture on the RP page. Here 'global' means information that cannot be used to identify a specific user. 11 | 12 | ## Preventing RP tracking 13 | In this flow the user agent attempts to mitigate [RP tracking](glossary.md#rp-tracking) by displaying a warning if the IDP is going to provide correlatable user identifiers to the RP. The warning is not shown if all identifiers in the profile are [verifiably directed](directed_identifiers.md#verifiably-directed-identifiers). 14 | 15 | ## User flow illustration 16 |
17 | 18 |
Simplified illustration of the permission-oriented user flow
19 |
20 | 21 | ## Benefits 22 | * This should work well across a variety of protocols and use cases without user agents having to accommodate them specifically. 23 | * For those reasons, IDPs and RPs can have control over sign-in experiences to improve user experiences as they see fit. 24 | * In cases where browser state is missing, the only experience downgrade is to have to agree to a cross-origin data sharing permission prompt again. 25 | 26 | ## Challenges 27 | * The user agent cannot differentiate cases where the IDP gave users the option to use directed identifiers but the user chose not to use them from cases where the user did not have the option to choose directed identifiers at all. In both cases, the data shared back via the browser isn’t verifiably directed and so the browser would require a RP tracking consent step for both. 28 | * From a UX perspective and ecosystem incentives perspective, we may want to differentiate the experience for each case. 29 | * This downside is not shared by [pure policy-based approaches](#rely-on-policy-based-enforcement-instead-of-directed-identifiers) or approaches with [browser mediation](mediation_oriented_api.md). 30 | * Revealing the RP to the IDP becomes a problem if, in the future, privacy restrictions are added on things like referrer on full page navigation. 31 | * If permission prompts are too frequent, users may become trained to click through them without thinking (viz. 'warning fatigue'). 32 | 33 | ## Mocks 34 | 35 |
36 | 37 |
Permission-oriented user flow mocks
38 |
39 | 40 | ## Other design options 41 | 42 | Below are possible variations on the permission-oriented API approach that can change the trade-offs. 43 | 44 | ### Rely on policy-based enforcement instead of directed identifiers 45 | This flow would change minimally if the user agent could accept an IDP's assertion on whether identifiers are directed without them conforming to a verifiable format (i.e. [policy-based enforcement](directed_identifiers.md#policy-based-approach)). This has the benefit of avoiding the [compatibility problems with verifiably directed identifiers](directed_identifiers.md#caveats-of-verifiably-directed-identifiers) but at the drawback of increasing tracking risk from a bad-faith IDP. 46 | 47 | There is always going to be some level of policy-based requirements, since a bad-faith IDP could collude with an RP outside of the defined flows to unmask directed identifiers, but verifiably directed identifiers might make it harder to do that at scale. 48 | 49 | ### IDP tracking gated on explicit user consent 50 | Another variation is to add a second 'consent moment' where the user grants permission up front for the RP to send a request to the IDP, and at that point IDP tracking becomes possible. The benefit of this approach is that it might be more resilient to future privacy enhancements that make it hard for an RP to initiate a flow where the IDP can learn the RP's origin (or in OIDC terms, client ID). The drawback is that the prompt needs to be shown before the user is shown IDP UI, necessitating two user agent prompts in some cases, since the RP tracking warning for non-directed identifiers has to come after the IDP UI. 51 | 52 | If this permission prompt is added, there is a further question of whether it should apply to an IDP universally (suggesting that the user trusts a given IDP to learn about any sites that offer federated sign-in) or whether the prompt should appear for every IDP+RP pair. The latter case would result in users only rarely seeing such a prompt: only once per IDP, as long as the user agent is able to persist that permission. The downside is that it increases user risk if a tracking site can convince the user to grant the permission. 53 | -------------------------------------------------------------------------------- /explorations/prior.md: -------------------------------------------------------------------------------- 1 | # Prior Art 2 | 3 | By far, the closest analogy to this work is the great work of [BrowserID](https://github.com/mozilla/id-specs/blob/prod/browserid/index.md#web-site-signin-flow) during the [Mozilla Personas](https://web.archive.org/web/20210124072422/https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Persona/The_navigator.id_API) effort ([postmortem](https://wiki.mozilla.org/Identity/Persona_AAR)). In many ways, the goals that BrowserID was trying to achieve as well as the mechanisms that were created are a lot like FedCM. There are significant differences in strategy and design, but let’s start with the similarities first because there are many. 4 | 5 | First, BrowserID was clearly trying to solve similar problems, namely IDP Tracking and friction. The mechanisms that were created clearly had [strong builtin privacy components](https://www.youtube.com/watch?v=qHpFwdQw2wQ) to prevent IDPs from knowing about RPs and vice versa, via the chain of signatures gathered from IDPs (mainly email providers) and certificates generated by the browser. 6 | 7 | Second, from a mechanism perspective, there was clearly a separation between an RP to Browser API as well as a Browser to IDP API. 8 | 9 | ```javascript 10 | navigator.id.get((assertion) => {}, { 11 | backgroundColor: "#606B72", 12 | siteName: "My Example Site" 13 | }); 14 | ``` 15 | 16 | The [RP calls a browser native API](https://github.com/mozilla/id-specs/blob/prod/browserid/index.md#web-site-signin-flow) to fetch an assertion which gets mediated by the [browser in coordination with the IDP](https://github.com/mozilla/id-specs/blob/prod/browserid/index.md#identity-provisioning-flow). 17 | 18 | ```javascript 19 | // set up UI 20 | navigator.id.beginAuthentication(function(email) { 21 | // update UI to display the email address 22 | }); 23 | ``` 24 | 25 | The [postmortem analysis](https://wiki.mozilla.org/Identity/Persona_AAR) is very insightful in understanding the challenges faced and gives this proposal a solid place to work from. In many ways, we think some of these insights are rooted in the observation we made earlier about backwards compatibility with RPs and user’s current behavior, which we are deliberately trying to avoid. 26 | 27 | 28 | # Related Work 29 | 30 | - [Building a More Private Web](https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html) 31 | - [Personas](https://wiki.mozilla.org/Identity/Persona_AAR) and [navigator.id](https://web.archive.org/web/20210124072422/https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Persona/The_navigator.id_API) 32 | - [WebOTP](https://github.com/WICG/WebOTP) 33 | - [Credential Manager](https://w3c.github.io/webappsec-credential-management/#federated) 34 | - Add your work [here](https://github.com/fedidcg/FedCM/issues/new) 35 | 36 | -------------------------------------------------------------------------------- /explorations/problem.md: -------------------------------------------------------------------------------- 1 | # The Problem 2 | 3 | Over the last decade, identity federation has played a central role in raising the bar for authentication on the web, in terms of ease-of-use (e.g. passwordless single sign-on), security (e.g. improved resistance to phishing and credential stuffing attacks) and trustworthiness compared to per-site usernames and passwords. 4 | 5 | The standards that define how identity federation works today on the Web were built independently of the Web Platform (namely, [SAML](https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language), [OpenID](https://en.wikipedia.org/wiki/OpenID) and [OAuth](https://en.wikipedia.org/wiki/OAuth)), and their designers worked within the Web's limitations. 6 | 7 | Because of those limitations, existing user authentication flows were designed on top of general-purpose web platform capabilities such as top-level navigations/redirects with parameters, window popups, iframes and cookies. 8 | 9 | Because those general purpose primitives can be used for an open-ended set of use cases (again, notably, by design), browsers have to apply policies that capture the **lowest common denominator** of abuse, at best applying cumbersome permissions (e.g. popup blockers) and, at worst, blocking primitives entirely (e.g. [blocking third-party cookies](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/)). 10 | 11 | Over the years, as low level primitives were abused, browsers intervened and federation adjusted. For example, popup blockers became common and federation adjusted to work in a world where popup blockers were widely deployed. 12 | 13 | The challenge, now more than ever, is that some of these low level primitives are increasingly abused to allow tracking users across websites. As a result, browsers are applying stricter and stricter policies around the primitives. 14 | 15 | > Publicly announced browser positions on third-party cookies: 16 | > 17 | > 1. [Safari](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/): third-party cookies are **already** blocked by **default** 18 | > 1. [Firefox](https://blog.mozilla.org/blog/2019/09/03/todays-firefox-blocks-third-party-tracking-cookies-and-cryptomining-by-default/): third-party cookies are **already** blocked **by a blocklist** 19 | > 1. [Chrome](https://blog.google/products/chrome/privacy-sustainability-and-the-importance-of-and/): on iOS **already** blocked **by default** and intends to offer **alternatives** to make them **obsolete** in the [near term](https://www.blog.google/products/chrome/building-a-more-private-web/) on other platforms. 20 | 21 | Blocking third-party cookies broke important parts of the protocols in those browsers (e.g. [logouts](https://www.identityserver.com/articles/the-challenge-of-building-saml-single-logout)) and made some user experiences inviable (e.g. [social button](https://developers.facebook.com/docs/facebook-login/userexperience/) and [widget personalization](https://developers.google.com/identity/gsi/web)). 22 | 23 | While it is easier to see the **current** impact of third-party cookies, it is equally important to understand the ways in which the low level primitives that identity federation depends on (e.g. redirects) are being abused and the [privacy principles](https://github.com/michaelkleber/privacy-model) browsers are using to increase control of those primitives, so that we don't paint ourselves into a corner. 24 | 25 | If browsers are applying stricter policies around the low level primitives that federation depends upon, but with the assumption that federation is significantly better than usernames/passwords, how do we continue to enable identity federation? 26 | 27 | 28 | ## Third-Party Cookies 29 | 30 | The problem starts with classification. 31 | 32 | When federation was first designed, it was designed **within** the existing capabilities of the web, rather than **changing** them. Specifically, federation worked with callbacks on top of **cookies**, **redirects**, **iframes** or **popup windows**. All are fundamental primitives provided by the web which didn't require any redesign, redeployment or negotiation with browser vendors. 33 | 34 | One example of a low level primitive that federation depends on is **iframes** and **third-party cookies**. For example, credentialed iframes are used while [logging out](https://openid.net/specs/openid-connect-rpinitiated-1_0.html), for [social buttons](https://developers.facebook.com/docs/facebook-login/userexperience/), and for [widget personalization](https://developers.google.com/identity/one-tap/web). 35 | 36 | ![](static/mock27.svg) 37 | 38 | Unfortunately, the use of iframes is virtually indistinguishable from trackers that can track browsing history across relying parties, just by having users visit links (e.g. loading credentialed iframes on page load). 39 | 40 | We call this **the classification problem** because it is hard for a browser to distinguish between these two cases: identity federation helping a user, versus users being tracked without any control. 41 | 42 | ![](static/mock26.svg) 43 | 44 | Third-party cookies are **already** blocked in [Safari](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/) and [Firefox](https://blog.mozilla.org/blog/2019/09/03/todays-firefox-blocks-third-party-tracking-cookies-and-cryptomining-by-default/) **by default** (and [Chrome](https://blog.google/products/chrome/privacy-sustainability-and-the-importance-of-and/) intends to block third-party cookies soon too) which makes these use cases inviable. 45 | 46 | The problems then are: 47 | 48 | 1. **First** and foremost, what Web Platform features need to be exposed to (re)enable these features of federation to co-exist with the absence of third-party cookies in browsers going forward? 49 | 2. **Secondarily**, in which direction are browsers going that could potentially impact federation? 50 | 51 | 52 | ## Navigational Tracking 53 | 54 | Before we prematurely jump into solutions for the first (and more **urgent**) problem, we think there is something more fundamental changing. Let's take a step back and a take closer look at the **second** problem: in which direction are browsers going that could more fundamentally impact federation? 55 | 56 | While third-party cookies in iframes are used in federation, a more fundamental low level primitive that federation uses is top level navigations (e.g. redirects or form POSTs) to navigate the user to identity providers (with callbacks, e.g. `redirect_uri`) and back to relying parties with a result (e.g. an `id_token`): 57 | 58 | ![](static/mock21.svg) 59 | 60 | This **low level** primitive also enables cross-site communication, namely via [decorating links](https://www.chromium.org/Home/chromium-privacy/privacy-sandbox), which can be abused to track users without their control. This is called **bounce tracking**: 61 | 62 | ![](static/mock22.svg) 63 | 64 | In this example of **bounce tracking**, websites redirect the user to a cross-origin website that automatically and invisibly redirects the user back to the caller, but passing enough information in URL parameters to enable the tracker to join that visit (e.g. when you visit `rings.com`) with visits to other websites (e.g. when you visit `shoes.com`). 65 | 66 | In federation, that's less invisible/automatic, but it is still there. Cross-site tracking is enabled via federation when relying parties that the user signs in to **collude** with each other (and other entities) to deterministically (or probabilistically) **link** their users' accounts to build a richer user profile (e.g. one site selling data on browsing history for ads targeting to another service). While this could be enabled without federation (users could manually provide a joinable email address or phone number), federated identity providers have an opportunity to address this problem at scale by providing their users with site-specific/directed identifiers. 67 | 68 | ![](../spec/img/mock3.svg) 69 | 70 | Because of these tracking risks, browsers are starting to disable third-party cookies in iframes and more generally provide tighter control over cross-site communication (e.g. a [privacy model](https://github.com/michaelkleber/privacy-model) for the web). 71 | 72 | Because this cross-site communication takes place in a general purpose medium, it is hard for browsers to distinguish between cross-site communication that is used for exchanging identity data deliberately (e.g. federation) or unintentionally (e.g. tracking). 73 | 74 | Browsers can't readily **classify** federation; federation is inherently intended to support many (or arbitrary) agents. 75 | 76 | The classification problem is notably hard because it has to deal with **adversarial impersonation**: agents who have an interest in being classified as federation to get access to browser affordances. 77 | 78 | While the timelines for aggressive browser defenses against bounce tracking are farther in the future, proposed defenses much more fundamentally threaten federation. 79 | 80 | > Publicly announced positions by browsers on bounce tracking: 81 | > 82 | > - Safari's existing deployed [strategies](https://webkit.org/blog/11338/cname-cloaking-and-bounce-tracking-defense/) and [principles](https://github.com/privacycg/proposals/issues/6) 83 | > - Firefox's protection against [redirect tracking](https://blog.mozilla.org/security/2020/08/04/firefox-79-includes-protections-against-redirect-tracking/) 84 | > - Chrome's stated [Privacy Model](https://github.com/michaelkleber/privacy-model) for the Web 85 | 86 | So, how do we **distinguish** federation from tracking and elevate the level of **control** while **assuming** adversarial impersonation? 87 | 88 | There is no one answer, but we have a [proposal](proposal.md) as a starting point. 89 | -------------------------------------------------------------------------------- /explorations/proposal.md: -------------------------------------------------------------------------------- 1 | # Proposal 2 | 3 | Clearly, this is a massive, multi-agent, multi-year problem across the board. 4 | 5 | There aren't any easy solutions and most of the answers come in the form of alternatives with trade-offs. 6 | 7 | There are billions of users that depend on federation on the web, millions/thousands of relying parties and thousands/hundreds of identity providers. There are also tens of browsers and operating systems, all moving independently. None of that changes overnight and we don't expect it to. 8 | 9 | The specs that define how federation works (e.g. OpenID, SAML, etc) are intricate and long (e.g. session management, authorization, etc). 10 | 11 | Having said that, failing to be proactive about effecting change-and making federation forward-compatible with a more private Web—can steer users to native apps or less secure patterns like usernames/passwords. 12 | 13 | The approach we have taken so far has been a combination of two strategies: 14 | 15 | - a **firm** and **principled** understanding of where we want to go 16 | - a **well-informed**, **deliberate** and **pragmatic** choice of what steps to take us there 17 | 18 | We believe a convincing path needs to have a clearly defined end state but also a plausible sequencing strategy. 19 | 20 | 1. Let's start with [where we want to be](#the-end-state), and then later 21 | 1. Go over [how we get there](#the-intermediate-states). 22 | 23 | ## The End State 24 | 25 | We believe that identity federation on the Web needs to be supported by a foundation that is in equal parts **opinionated** and **extensible**. 26 | 27 | We believe that identity federation on the Web needs to be **free of unintended tracking consequences**. 28 | 29 | By that we mean: 30 | 31 | * **The RP Tracking Problem**: Websites shouldn't be able to join your identities by default and without your control. 32 | * **The IDP Tracking Problem**: Identity Providers shouldn't be able to be involved without justification by default and without your control. 33 | 34 | ![](static/mock36.svg) 35 | 36 | In the future, we'll have two fundamentally different things: consequence-free defaults and control. Identity federation on a Web that is narrowly private by default and broadly identifying by choice. 37 | 38 | > We don't believe these to be much different from the properties that Kim Cameron identified in the [7 laws of identity](https://www.identityblog.com/stories/2005/05/13/TheLawsOfIdentity.pdf), namely the "User Control and Consent", "Minimal Disclosure for a Constrained Use", "Justifiable Parties" and the "Directed Identity" laws. 39 | 40 | The principle used as a foundation to effect change on the defaults and controls is that cross-origin communication is a privileged operation and needs to be intermediated by the user agent. 41 | 42 | > When there is a conflict of interests for the parties involved, we think the following is the right order of constituencies: [users first](https://www.w3.org/TR/html-design-principles/#priority-of-constituencies), developers second (relying parties and identity providers, in that order), browser engines third, and technical purity fourth. 43 | 44 | In the future, the user agent will intermediate and assist in the cross-origin exchange of identification by picking better defaults in two ways: 45 | 46 | 1. **The RP Tracking Mitigation**: Unbundling your **global** identity into multiple **directed** identities per-site. 47 | 1. **The IDP Tracking Mitigation**: Unbundling the **issuing** of credentials with their **presentation**. 48 | 49 | ![](../spec/img/mock37.svg) 50 | 51 | The first principle can be solved by the user agent insisting on a progressive disclosure of identification, starting with the minimal disclosure for the most constrained use (e.g. a directed identifier that is recoverable between devices) towards progressively and contextually exposing information (e.g. giving access to your calendar): 52 | 53 | ![](static/mock33.svg) 54 | 55 | The second principle (unbundling the issuer from the holder of credentials) is more technically involved, but has a real world analog: driver's licenses. 56 | 57 | When you present your driver's license as a form of identification to, say, a store that needs to check your age, the government issuer of the driver's license isn't involved (and its involvement doesn't seem to be justified). The **presentation** of your driver's license is decoupled from the **issuing** of your driver's license. 58 | 59 | We believe that unbundling these operations, means users can use their credentials without **necessarily** phone-homing to their issuers: 60 | 61 | ![](../spec/img/mock34.svg) 62 | 63 | 64 | ### The Delegation-oriented API 65 | 66 | So far, none of these are original ideas. Proxying email addresses and directing identifiers is a norm for some identity providers and self-issuing credentials has been proposed by [BrowserID](prior.md) for example. 67 | 68 | However, while these ideas exist in isolation, a system that combines them is hard. 69 | 70 | We call the active investigation of a protocol that can solve both of these problems (as well as recovery) the **Delegation-oriented Model**. Without much explanation (full details [here](https://docs.google.com/document/d/1ZymcC2ABSzwJloXje5R_KFLi0-Vaz03iLR9DjwQl9u0/edit)), here is a glimpse of what that may look like: 71 | 72 | ![](static/mock38.svg) 73 | 74 | The Delegation-oriented Model is very compelling as an end-state for FedCM because it solves both tracking problems. Because it solves both tracking issues, it doesn't have any unintended tracking consequence. 75 | 76 | Because it is **consequence-free**, we expect it to be **permission-less** (the best permission is the one that isn't needed) and comparably better for users with formulations that impose on the user to make a determination on the consequences of being tracked. 77 | 78 | The Delegation-oriented Model isn't free of challenges though. Its weakest point is that it is (a) not backwards compatible with the current deployment of federation on the Web and (b) not perfectly clear if the incentives are well aligned to establish an economic equilibrium. 79 | 80 | While not all of the pieces are put together, we think the Delegation-oriented model represents the northstar that we aspire to. 81 | 82 | These problems, as well as others, are being explored more in-depth [here](https://docs.google.com/document/d/1ZymcC2ABSzwJloXje5R_KFLi0-Vaz03iLR9DjwQl9u0/edit). 83 | 84 | 85 | ## The Intermediate States 86 | 87 | There are a large number of mid-game states between the opening and the endgame for FedCM. 88 | 89 | It is unclear how many of these are sustainable/desirable long-term, and how they will evolve, but their existence for a non-trivial amount of time is non-neglectable. 90 | 91 | For the most part, these states are a trade-off between backwards compatibility (for users, relying parties and identity providers, in that order) and effective controls (ignorable permission prompts, mediation, and removing the tracking risks altogether, in that order). 92 | 93 | Our best guess at the moment is that each of these three variations (delegation, mediation and permission) have different trade-offs that don't put them at mutually exclusive positions, meaning we could imagine a state where all of these three variations co-exist. 94 | 95 | So, having said that, let's start from most backwards compatible to least. 96 | 97 | * [The Permission-oriented API](#the-permission-oriented-api) 98 | * [The Mediated-oriented API](#the-mediated-oriented-api) 99 | 100 | 101 | ### The Permission-oriented API 102 | 103 | It is clearly highly desirable to minimize deployment costs: the less asked of developers (while keeping/raising the privacy bar), the better. 104 | 105 | That's what the HTTP API is all about: backwards compatibility. 106 | 107 | We're still exploring this space, trying to understand if it's possible to classify federation with zero changes in the ecosystem. 108 | 109 | Because a significant part of federation is deployed over well-established protocols (e.g. OpenID, SAML), their HTTP profile is somewhat easy to spot. For example, for OpenID Connect requests/responses the HTTP requests have: 110 | 111 | - a **client_id** parameter 112 | - a **redirect_uri** parameter 113 | - a **scope** parameter 114 | - an accompanying **.well-known/openid-configuration** configuration 115 | 116 | In this formulation, a user agent could intercept HTTP requests made in this fashion and provide permission prompts to gather the user's intent to sign in and hence, for example, allow the request to be made credentialed with cookies: 117 | 118 | ![](static/mock39.gif) 119 | 120 | The way back from the IDP to the RP is also highly structured, so responses can be classified (and made credentialed) when they match: 121 | 122 | - a redirect to the previously used **redirect_uri** 123 | - an **id_token** parameter 124 | 125 | Notably, for cases where the IDP controls the deployment of the JavaScript running on the RP page (typically opening a popup window), we are also exploring offering a more explicit API, such as: 126 | 127 | ```javascript 128 | // This is just a possible starting point, largely TBD. 129 | // 130 | // Note, this historical, see https://w3c-fedid.github.io/FedCM for the current API. 131 | // 132 | let {idToken} = await navigator.credentials.get({ 133 | provider: 'https://accounts.example.com', 134 | 'ux_mode': 'permission', 135 | // other OpenId connect parameters 136 | }); 137 | ``` 138 | 139 | So, to sum up: 140 | 141 | * **Pros**: most backward-compatible. 142 | * **Cons**: permissions aren't expected to be the most effective way to offer privacy controls. 143 | 144 | 145 | ### The Mediated-oriented API 146 | 147 | Another potential step, somewhere in the middle of backwards compatibility and privacy control, is what we've been calling the Mediated-oriented API. 148 | 149 | In this formulation, the triggering of the API works similarly as before, but the execution is done in an intermediated fashion: 150 | 151 | ```javascript 152 | // This is just a possible starting point, largely TBD. 153 | // 154 | // Note, this historical, see https://w3c-fedid.github.io/FedCM for the current API. 155 | // 156 | let {idToken} = await navigator.credentials.get({ 157 | provider: 'https://accounts.example.com', 158 | 'ux_mode': 'mediation', 159 | // other OpenId connect parameters 160 | }); 161 | ``` 162 | 163 | This is accomplished via an HTTP protocol between the IDP and the User-Agent ([under exploration](HOWTO.md#identity-provider-implementation)): 164 | 165 | ![](static/mock40.gif) 166 | 167 | The mediated-oriented API offers a balance between trade-offs: 168 | 169 | * **Pros**: backwards compatible with relying parties (which are many), requires work from the IDP (which are few). Largely backwards compatible from a user experience/behavior/norm perspective. Privacy controls are offered contextually. 170 | * **Cons**: takes on some of the responsibility for the user agent (e.g. account chooser), which affects the autonomy of IDPs and RPs. 171 | -------------------------------------------------------------------------------- /explorations/related_problems.md: -------------------------------------------------------------------------------- 1 | # Related Problems 2 | 3 | Authentication and authorization is a large problem space. There are 4 | several related federation issues where the browser maybe able to 5 | provide an enhanced experience. 6 | 7 | ## The [NASCAR flag](https://developers.google.com/identity/toolkit/web/federated-login#the_nascar_page) problem 8 | 9 | Every website has a different sign-in process and has to show a list of supported identity providers for users to pick from. The user is left to determine which identity provider to choose. The implications of their choice may be significant: choosing a different option than they chose last time might create a new account, and picking a different provider may result in different data getting shared. Typically, the user must make their selection without any support from the browser in remembering their past choice or highlighting relevant options. We believe that, by pulling some of the responsibility into the browser, we can offer a personalized IDP disambiguation UI which can lead to higher conversion rates, while maintaining user privacy. 10 | 11 | ![](static/mock12.svg) 12 | 13 | 14 | ## Identity Attribute Verification 15 | 16 | Verifying phone numbers and emails is tedious: currently, verification is often done manually by users without assistance from the browser or IDP. For example, to verify email addresses, a service typically sends an OTP (one-time code) to the user’s inbox to be copied/pasted. Similarly, for phone numbers, an SMS message is sent to the user’s phone to be copied/pasted too. There are clear ways here where the browser can step in to help (e.g. [WebOTP](https://github.com/WICG/WebOTP)), and it would generally be preferable for authoritative identity providers to leverage these features wherever possible. 17 | 18 | 19 | ## Cross-device sign-in 20 | 21 | Because cookies are not propagated across devices, a user has to sign in (and remember account info, etc.) on new devices. Often they end up going through a recovery flow, creating a duplicate account, or abandoning sign-in completely. Identity providers play an important role in facilitating cross-device sign-in, but we may be able to solve this more generally for users irrespective of their chosen authentication mechanism, by expanding on Web Platform functionality such as the [Credential Management API](https://www.w3.org/TR/credential-management-1/). 22 | 23 | 24 | ## The Session State Opacity Problem 25 | 26 | Because session state management is implemented via general purpose low-level primitives (namely, cookies), when users intend to “log-out”, there are no guarantees that anything necessarily happens (e.g. the origin can still identify the user while pretending that it cannot). Currently, only clearing all cookies makes it significantly harder for an origin to **adversarially track** a user post log-out. There are proposals such as [IsLoggedIn](https://github.com/WebKit/explainers/tree/master/IsLoggedIn) to address this issue. 27 | 28 | ![](../spec/img/mock5.svg) 29 | -------------------------------------------------------------------------------- /explorations/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | While [the end state](proposal.md#the-end-state) gives us guidance of where to aim, an equally hard problem is to find a plausible path to that state. 4 | 5 | While much of the environment is changing and evolving, there are concrete flows that are inviable **right now** and enough signals about the principles and challenges **ahead** of us. 6 | 7 | Much of this is evolving quickly and we are adapting as we learn, but here is our best representation of how we expect features to be developed: 8 | 9 | | Stage | Timeline | Description | 10 | |-----------------------------------------|-----------|----------------------------------------------| 11 | | [Stage 0](problem.md) | 2020 | Understanding of the [problem](problem.md) and [properties](https://github.com/michaelkleber/privacy-model) of the end state | 12 | | [Stage 1](#stage-1-third-party-cookies) | 2021 | [dev trials](https://docs.google.com/document/d/1_FDhuZA_C6iY5bop-bjlPl3pFiqu8oFvuK1jzAcyWKU/edit#heading=h.t4ac0nsw5yo) in Q1/Q2 ([instructions](HOWTO.md)) and [origin trials](https://sites.google.com/a/chromium.org/dev/blink/origin-trials) in Q3/Q4 of alternatives to [third-party cookies](#stage-1-third-party-cookies) | 13 | | [Stage 2](#stage-2-bounce-tracking) | 2021+ | [origin trials](https://sites.google.com/a/chromium.org/dev/blink/origin-trials) of alternatives to [top level navigation](#stage-2-bounce-tracking) | 14 | | [Stage 3](#stage-3-future-work) | 2021++ | other [related problems](related_problems.md) and opportunities | 15 | 16 | 17 | ## Stage 1: Third-Party Cookies 18 | 19 | The more urgent problem that clearly has **already** affected federation is the blocking of third-party cookies. We plan to tackle this first: 20 | 21 | - **Why**, **What** and **When**? Today, third-party cookies are blocked on [Safari](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/) and [Firefox](https://blog.mozilla.org/blog/2019/09/03/todays-firefox-blocks-third-party-tracking-cookies-and-cryptomining-by-default/). They are in the process of becoming **obsolete** in [Chrome](https://blog.google/products/chrome/privacy-sustainability-and-the-importance-of-and/) in the foreseeable future. 22 | - So **What**? [Logging out](https://openid.net/specs/openid-connect-rpinitiated-1_0.html), [social buttons](https://developers.facebook.com/docs/facebook-login/userexperience/) and [widget personalization](https://developers.google.com/identity/one-tap/web) breaks. 23 | - Ok ... Now **What**? [Early proposals](cookies.md) on how to preserve these use cases. 24 | - **Who** and **Where**?: Browser vendors, identity providers, relying parties and standard bodies are involved. The discussions so far have happened at the [WICG](https://github.com/WICG/FedCM/issues) and at the [OpenID foundation](https://github.com/IDBrowserUseCases/docs). 25 | 26 | 27 | ## Stage 2: Bounce Tracking 28 | 29 | Bounce tracking comes next. It is a more evolving situation, but has much more profound implications to federation: 30 | 31 | - **Why**, **What** and **When**? Safari's [periodic storage purging](https://webkit.org/blog/11338/cname-cloaking-and-bounce-tracking-defense/) and [SameSite=Strict jail](https://github.com/privacycg/proposals/issues/6), Firefox's [periodic storage purging](https://blog.mozilla.org/security/2020/08/04/firefox-79-includes-protections-against-redirect-tracking/) and Chrome's stated [privacy model](https://github.com/michaelkleber/privacy-model) for the Web. 32 | - So **What**? Purging or partitioning storage across redirects/posts forces users to re-authenticate at each transition of federation flows, at best defeating the convenience that federation provides and at worst making it less secure. 33 | - OK ... Now **What**? [Early proposals](navigations.md) on how to preserve these use cases. 34 | - **Who** and **Where**?: Browser vendors, identity providers, relying parties and standards bodies are involved. The discussions so far have happened at the [WICG](https://github.com/WICG/FedCM/issues) and at the [OpenID Foundation](https://github.com/IDBrowserUseCases/docs). 35 | 36 | 37 | ## Stage 3: Future Work 38 | 39 | There is a series of [related problems](related_problems.md) that affect federation. We believe we have a unique opportunity to tackle these as a consequence of the choices made in stages 1 and 2. 40 | 41 | These are key and important problems, but a lot less urgent, so we are being very deliberate about **when** and **how much** to focus on them. 42 | -------------------------------------------------------------------------------- /explorations/static/anchor-js.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AnchorJS - v3.2.0 - 2016-06-10 3 | * https://github.com/bryanbraun/anchorjs 4 | * Copyright (c) 2016 Bryan Braun; Licensed MIT 5 | */ 6 | "use strict";!function(A,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){function A(A){function e(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function t(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}function n(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style"),t=" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",n=" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",o=' @font-face { font-family: "anchorjs-icons"; font-style: normal; font-weight: normal; src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBTUAAAC8AAAAYGNtYXAWi9QdAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zgq29TcAAAF4AAABNGhlYWQEZM3pAAACrAAAADZoaGVhBhUDxgAAAuQAAAAkaG10eASAADEAAAMIAAAAFGxvY2EAKACuAAADHAAAAAxtYXhwAAgAVwAAAygAAAAgbmFtZQ5yJ3cAAANIAAAB2nBvc3QAAwAAAAAFJAAAACAAAwJAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpywPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6cv//f//AAAAAAAg6cv//f//AAH/4xY5AAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACADEARAJTAsAAKwBUAAABIiYnJjQ/AT4BMzIWFxYUDwEGIicmND8BNjQnLgEjIgYPAQYUFxYUBw4BIwciJicmND8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFA8BDgEjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAEAAAABAACiToc1Xw889QALBAAAAAAA0XnFFgAAAADRecUWAAAAAAJTAsAAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAAlMAAQAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAACAAAAAoAAMQAAAAAACgAUAB4AmgABAAAABQBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEADgAAAAEAAAAAAAIABwCfAAEAAAAAAAMADgBLAAEAAAAAAAQADgC0AAEAAAAAAAUACwAqAAEAAAAAAAYADgB1AAEAAAAAAAoAGgDeAAMAAQQJAAEAHAAOAAMAAQQJAAIADgCmAAMAAQQJAAMAHABZAAMAAQQJAAQAHADCAAMAAQQJAAUAFgA1AAMAAQQJAAYAHACDAAMAAQQJAAoANAD4YW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQByYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format("truetype"); }',i=" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }";e.className="anchorjs",e.appendChild(document.createTextNode("")),A=document.head.querySelector('[rel="stylesheet"], style'),void 0===A?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(t,e.sheet.cssRules.length),e.sheet.insertRule(n,e.sheet.cssRules.length),e.sheet.insertRule(i,e.sheet.cssRules.length),e.sheet.insertRule(o,e.sheet.cssRules.length)}}this.options=A||{},this.elements=[],e(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var o,i,s,a,r,c,l,h,u,g,B,f,d=[];if(e(this.options),f=this.options.visible,"touch"===f&&(f=this.isTouchDevice()?"always":"hover"),A||(A="h1, h2, h3, h4, h5, h6"),o=t(A),0===o.length)return!1;for(n(),i=document.querySelectorAll("[id]"),s=[].map.call(i,function(A){return A.id}),r=0;r-1,t=A.lastChild&&(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ")>-1;return e||t||!1}}return A}); 7 | -------------------------------------------------------------------------------- /explorations/static/droid.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Droid Serif'; 3 | font-style: italic; 4 | font-weight: 400; 5 | src: local('Droid Serif Italic'), local('DroidSerif-Italic'), url(//fonts.gstatic.com/s/droidserif/v9/tDbK2oqRg1oM3QBjjcaDkOr4nAfcGw.ttf) format('truetype'); 6 | } 7 | @font-face { 8 | font-family: 'Droid Serif'; 9 | font-style: normal; 10 | font-weight: 400; 11 | src: local('Droid Serif Regular'), local('DroidSerif-Regular'), url(//fonts.gstatic.com/s/droidserif/v9/tDbI2oqRg1oM3QBjjcaDkOr9rAA.ttf) format('truetype'); 12 | } 13 | @font-face { 14 | font-family: 'Droid Serif'; 15 | font-style: normal; 16 | font-weight: 700; 17 | src: local('Droid Serif Bold'), local('DroidSerif-Bold'), url(//fonts.gstatic.com/s/droidserif/v9/tDbV2oqRg1oM3QBjjcaDkOJGiRD7OwQ.ttf) format('truetype'); 18 | } 19 | @font-face { 20 | font-family: 'Source Sans Pro'; 21 | font-style: italic; 22 | font-weight: 400; 23 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(//fonts.gstatic.com/s/sourcesanspro/v11/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDc.ttf) format('truetype'); 24 | } 25 | @font-face { 26 | font-family: 'Source Sans Pro'; 27 | font-style: normal; 28 | font-weight: 400; 29 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(//fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7g.ttf) format('truetype'); 30 | } 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | font-style: normal; 34 | font-weight: 600; 35 | src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(//fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdr.ttf) format('truetype'); 36 | } 37 | @font-face { 38 | font-family: 'Source Sans Pro'; 39 | font-style: normal; 40 | font-weight: 700; 41 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(//fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdr.ttf) format('truetype'); 42 | } 43 | @font-face { 44 | font-family: 'Source Sans Pro'; 45 | font-style: normal; 46 | font-weight: 900; 47 | src: local('Source Sans Pro Black'), local('SourceSansPro-Black'), url(//fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3iu4nwlxdr.ttf) format('truetype'); 48 | } 49 | -------------------------------------------------------------------------------- /explorations/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/favicon.ico -------------------------------------------------------------------------------- /explorations/static/google-sans.css: -------------------------------------------------------------------------------- 1 | /* 2 | * See: https://fonts.google.com/license/googlerestricted 3 | */ 4 | /* cyrillic */ 5 | @font-face { 6 | font-family: 'Google Sans'; 7 | font-style: italic; 8 | font-weight: 400; 9 | src: local('Google Sans Italic'), local('GoogleSans-Italic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaErENHsxJlGDuGo1OIlL3L8phULilENlYQ_Q.woff2) format('woff2'); 10 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 11 | } 12 | /* greek */ 13 | @font-face { 14 | font-family: 'Google Sans'; 15 | font-style: italic; 16 | font-weight: 400; 17 | src: local('Google Sans Italic'), local('GoogleSans-Italic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaErENHsxJlGDuGo1OIlL3L8p9ULilENlYQ_Q.woff2) format('woff2'); 18 | unicode-range: U+0370-03FF; 19 | } 20 | /* vietnamese */ 21 | @font-face { 22 | font-family: 'Google Sans'; 23 | font-style: italic; 24 | font-weight: 400; 25 | src: local('Google Sans Italic'), local('GoogleSans-Italic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaErENHsxJlGDuGo1OIlL3L8pNULilENlYQ_Q.woff2) format('woff2'); 26 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 27 | } 28 | /* latin-ext */ 29 | @font-face { 30 | font-family: 'Google Sans'; 31 | font-style: italic; 32 | font-weight: 400; 33 | src: local('Google Sans Italic'), local('GoogleSans-Italic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaErENHsxJlGDuGo1OIlL3L8pJULilENlYQ_Q.woff2) format('woff2'); 34 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 35 | } 36 | /* latin */ 37 | @font-face { 38 | font-family: 'Google Sans'; 39 | font-style: italic; 40 | font-weight: 400; 41 | src: local('Google Sans Italic'), local('GoogleSans-Italic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaErENHsxJlGDuGo1OIlL3L8pxULilENlY.woff2) format('woff2'); 42 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 43 | } 44 | /* cyrillic */ 45 | @font-face { 46 | font-family: 'Google Sans'; 47 | font-style: italic; 48 | font-weight: 500; 49 | src: local('Google Sans Medium Italic'), local('GoogleSans-MediumItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-m93OwBmO3wq9IqeuA.woff2) format('woff2'); 50 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 51 | } 52 | /* greek */ 53 | @font-face { 54 | font-family: 'Google Sans'; 55 | font-style: italic; 56 | font-weight: 500; 57 | src: local('Google Sans Medium Italic'), local('GoogleSans-MediumItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-m93OwdmO3wq9IqeuA.woff2) format('woff2'); 58 | unicode-range: U+0370-03FF; 59 | } 60 | /* vietnamese */ 61 | @font-face { 62 | font-family: 'Google Sans'; 63 | font-style: italic; 64 | font-weight: 500; 65 | src: local('Google Sans Medium Italic'), local('GoogleSans-MediumItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-m93OwtmO3wq9IqeuA.woff2) format('woff2'); 66 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 67 | } 68 | /* latin-ext */ 69 | @font-face { 70 | font-family: 'Google Sans'; 71 | font-style: italic; 72 | font-weight: 500; 73 | src: local('Google Sans Medium Italic'), local('GoogleSans-MediumItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-m93OwpmO3wq9IqeuA.woff2) format('woff2'); 74 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 75 | } 76 | /* latin */ 77 | @font-face { 78 | font-family: 'Google Sans'; 79 | font-style: italic; 80 | font-weight: 500; 81 | src: local('Google Sans Medium Italic'), local('GoogleSans-MediumItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-m93OwRmO3wq9Io.woff2) format('woff2'); 82 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 83 | } 84 | /* cyrillic */ 85 | @font-face { 86 | font-family: 'Google Sans'; 87 | font-style: italic; 88 | font-weight: 700; 89 | src: local('Google Sans Bold Italic'), local('GoogleSans-BoldItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-idxOwBmO3wq9IqeuA.woff2) format('woff2'); 90 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 91 | } 92 | /* greek */ 93 | @font-face { 94 | font-family: 'Google Sans'; 95 | font-style: italic; 96 | font-weight: 700; 97 | src: local('Google Sans Bold Italic'), local('GoogleSans-BoldItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-idxOwdmO3wq9IqeuA.woff2) format('woff2'); 98 | unicode-range: U+0370-03FF; 99 | } 100 | /* vietnamese */ 101 | @font-face { 102 | font-family: 'Google Sans'; 103 | font-style: italic; 104 | font-weight: 700; 105 | src: local('Google Sans Bold Italic'), local('GoogleSans-BoldItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-idxOwtmO3wq9IqeuA.woff2) format('woff2'); 106 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 107 | } 108 | /* latin-ext */ 109 | @font-face { 110 | font-family: 'Google Sans'; 111 | font-style: italic; 112 | font-weight: 700; 113 | src: local('Google Sans Bold Italic'), local('GoogleSans-BoldItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-idxOwpmO3wq9IqeuA.woff2) format('woff2'); 114 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 115 | } 116 | /* latin */ 117 | @font-face { 118 | font-family: 'Google Sans'; 119 | font-style: italic; 120 | font-weight: 700; 121 | src: local('Google Sans Bold Italic'), local('GoogleSans-BoldItalic'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaZrENHsxJlGDuGo1OIlL3L-idxOwRmO3wq9Io.woff2) format('woff2'); 122 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 123 | } 124 | /* cyrillic */ 125 | @font-face { 126 | font-family: 'Google Sans'; 127 | font-style: normal; 128 | font-weight: 400; 129 | src: local('Google Sans Regular'), local('GoogleSans-Regular'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaGrENHsxJlGDuGo1OIlL3Kwp5eKQtGBlc.woff2) format('woff2'); 130 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 131 | } 132 | /* greek */ 133 | @font-face { 134 | font-family: 'Google Sans'; 135 | font-style: normal; 136 | font-weight: 400; 137 | src: local('Google Sans Regular'), local('GoogleSans-Regular'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaGrENHsxJlGDuGo1OIlL3Nwp5eKQtGBlc.woff2) format('woff2'); 138 | unicode-range: U+0370-03FF; 139 | } 140 | /* vietnamese */ 141 | @font-face { 142 | font-family: 'Google Sans'; 143 | font-style: normal; 144 | font-weight: 400; 145 | src: local('Google Sans Regular'), local('GoogleSans-Regular'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaGrENHsxJlGDuGo1OIlL3Bwp5eKQtGBlc.woff2) format('woff2'); 146 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 147 | } 148 | /* latin-ext */ 149 | @font-face { 150 | font-family: 'Google Sans'; 151 | font-style: normal; 152 | font-weight: 400; 153 | src: local('Google Sans Regular'), local('GoogleSans-Regular'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaGrENHsxJlGDuGo1OIlL3Awp5eKQtGBlc.woff2) format('woff2'); 154 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 155 | } 156 | /* latin */ 157 | @font-face { 158 | font-family: 'Google Sans'; 159 | font-style: normal; 160 | font-weight: 400; 161 | src: local('Google Sans Regular'), local('GoogleSans-Regular'), url(https://fonts.gstatic.com/s/googlesans/v14/4UaGrENHsxJlGDuGo1OIlL3Owp5eKQtG.woff2) format('woff2'); 162 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 163 | } 164 | /* cyrillic */ 165 | @font-face { 166 | font-family: 'Google Sans'; 167 | font-style: normal; 168 | font-weight: 500; 169 | src: local('Google Sans Medium'), local('GoogleSans-Medium'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLU94Yt3CwZsPF4oxIs.woff2) format('woff2'); 170 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 171 | } 172 | /* greek */ 173 | @font-face { 174 | font-family: 'Google Sans'; 175 | font-style: normal; 176 | font-weight: 500; 177 | src: local('Google Sans Medium'), local('GoogleSans-Medium'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLU94YtwCwZsPF4oxIs.woff2) format('woff2'); 178 | unicode-range: U+0370-03FF; 179 | } 180 | /* vietnamese */ 181 | @font-face { 182 | font-family: 'Google Sans'; 183 | font-style: normal; 184 | font-weight: 500; 185 | src: local('Google Sans Medium'), local('GoogleSans-Medium'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLU94Yt8CwZsPF4oxIs.woff2) format('woff2'); 186 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 187 | } 188 | /* latin-ext */ 189 | @font-face { 190 | font-family: 'Google Sans'; 191 | font-style: normal; 192 | font-weight: 500; 193 | src: local('Google Sans Medium'), local('GoogleSans-Medium'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLU94Yt9CwZsPF4oxIs.woff2) format('woff2'); 194 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 195 | } 196 | /* latin */ 197 | @font-face { 198 | font-family: 'Google Sans'; 199 | font-style: normal; 200 | font-weight: 500; 201 | src: local('Google Sans Medium'), local('GoogleSans-Medium'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLU94YtzCwZsPF4o.woff2) format('woff2'); 202 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 203 | } 204 | /* cyrillic */ 205 | @font-face { 206 | font-family: 'Google Sans'; 207 | font-style: normal; 208 | font-weight: 700; 209 | src: local('Google Sans Bold'), local('GoogleSans-Bold'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLV154t3CwZsPF4oxIs.woff2) format('woff2'); 210 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 211 | } 212 | /* greek */ 213 | @font-face { 214 | font-family: 'Google Sans'; 215 | font-style: normal; 216 | font-weight: 700; 217 | src: local('Google Sans Bold'), local('GoogleSans-Bold'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLV154twCwZsPF4oxIs.woff2) format('woff2'); 218 | unicode-range: U+0370-03FF; 219 | } 220 | /* vietnamese */ 221 | @font-face { 222 | font-family: 'Google Sans'; 223 | font-style: normal; 224 | font-weight: 700; 225 | src: local('Google Sans Bold'), local('GoogleSans-Bold'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLV154t8CwZsPF4oxIs.woff2) format('woff2'); 226 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 227 | } 228 | /* latin-ext */ 229 | @font-face { 230 | font-family: 'Google Sans'; 231 | font-style: normal; 232 | font-weight: 700; 233 | src: local('Google Sans Bold'), local('GoogleSans-Bold'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLV154t9CwZsPF4oxIs.woff2) format('woff2'); 234 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 235 | } 236 | /* latin */ 237 | @font-face { 238 | font-family: 'Google Sans'; 239 | font-style: normal; 240 | font-weight: 700; 241 | src: local('Google Sans Bold'), local('GoogleSans-Bold'), url(https://fonts.gstatic.com/s/googlesans/v14/4UabrENHsxJlGDuGo1OIlLV154tzCwZsPF4o.woff2) format('woff2'); 242 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 243 | } 244 | -------------------------------------------------------------------------------- /explorations/static/idp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /explorations/static/index.css: -------------------------------------------------------------------------------- 1 | html, body, .header { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, body { 7 | min-height: 100%; 8 | /** overflow: initial !important; **/ 9 | } 10 | 11 | body { 12 | /** font-family: "Droid Serif", Georgia, serif; **/ 13 | font-family: Google Sans,Roboto,Arial,Helvetica,sans-serif; 14 | -webkit-font-smoothing: antialiased; 15 | font-size: 20px; 16 | color: #333333; 17 | background-color: white; 18 | overflow-y: hidden; 19 | 20 | counter-reset: figures; 21 | } 22 | 23 | img { 24 | max-width: 100%; 25 | } 26 | 27 | figure { 28 | display: flex; 29 | flex-flow: column; 30 | padding: 5px; 31 | } 32 | 33 | figcaption { 34 | counter-increment: figures; 35 | 36 | font: italic smaller sans-serif; 37 | padding: 3px; 38 | text-align: center; 39 | } 40 | 41 | figcaption:before { 42 | content: 'Figure ' counter(figures) ' - '; 43 | font-weight: bold; 44 | } 45 | 46 | .header { 47 | /** box-shadow: 0 4px 12px 0 rgba(0, 0, 0, .05) !important; **/ 48 | box-shadow: 0 2px 6px 0 rgba(0,0,0,.12), inset 0 -1px 0 0 #dadce0; 49 | padding: 1em; 50 | /** position: fixed; **/ 51 | /** width: 100%; **/ 52 | top: 0; 53 | background-color: white; 54 | } 55 | 56 | main { 57 | /** margin: 64px auto auto; **/ 58 | margin: auto; 59 | /** padding: 2em; **/ 60 | position: absolute; 61 | /** width: 100%; **/ 62 | overflow-y: scroll; 63 | /** overflow-x: hidden; **/ 64 | top: 64px; 65 | bottom: 0px; 66 | right: 0px; 67 | left: 0px; 68 | outline: none; 69 | /** background-color: white; **/ 70 | } 71 | 72 | /** 73 | main, 74 | .header .container { 75 | max-width: 740px; 76 | margin: auto; 77 | } 78 | **/ 79 | 80 | .header .navigation { 81 | float: right; 82 | color: #555; 83 | /** margin-right: 1em; **/ 84 | } 85 | 86 | .header .title { 87 | font-size: 1.3125rem; 88 | font-weight: 500; 89 | /** font-family: "Roboto", "Helvetica", "Arial", sans-serif; **/ 90 | line-height: 1.16667em; 91 | } 92 | 93 | .title { 94 | /** margin-left: -5em; **/ 95 | } 96 | 97 | .header .navigation a { 98 | color: unset; 99 | /** text-decoration: none; **/ 100 | margin-right: 1em; 101 | } 102 | 103 | .navigation { 104 | /** margin-right: 1em; **/ 105 | } 106 | 107 | .header .title a, 108 | .catalogue-title a, 109 | .catalogue-body a { 110 | text-decoration: none; 111 | color: unset; 112 | } 113 | 114 | main { 115 | /** padding-top: 6em; **/ 116 | } 117 | 118 | .catalogue-item { 119 | border-bottom: 1px solid #e5e5e5; 120 | color: #333333; 121 | display: inline-block; 122 | padding: 1rem 0; 123 | width: 100%; 124 | } 125 | 126 | .catalogue-time { 127 | color: #aaa; 128 | letter-spacing: .5px; 129 | font-size: 0.7em; 130 | text-transform: uppercase; 131 | } 132 | 133 | .catalogue-title { 134 | font-size: 2em; 135 | line-height: 2em; 136 | /** font-family: "Source Sans Pro", sans-serif; **/ 137 | font-weight: 900; 138 | margin: 0; 139 | display: flex; 140 | margin-bottom: 0.25em; 141 | } 142 | 143 | .catalogue-title a { 144 | overflow: hidden; 145 | text-overflow: ellipsis; 146 | white-space: nowrap; 147 | } 148 | 149 | .catalogue-body { 150 | line-height: 1.8em; 151 | } 152 | 153 | .pagination { 154 | padding-top: 30px; 155 | padding-bottom: 30px; 156 | clear: both; 157 | } 158 | 159 | .pagination .left { 160 | float: left; 161 | } 162 | 163 | .pagination .right { 164 | float: right; 165 | } 166 | 167 | footer { 168 | text-align: center; 169 | margin-top: 2em; 170 | /** padding-bottom: 30px; **/ 171 | border-top: 1px solid #dadce0; 172 | height: 4em; 173 | bottom: 0px; 174 | background-color: #f8f9fa; 175 | } 176 | 177 | /** 178 | * Link placement and hover behavior. 179 | */ 180 | 181 | .anchorjs-link { 182 | color: inherit !important; 183 | text-decoration: none !important; /* do not underline */ 184 | } 185 | 186 | @media (max-width: 768px) { 187 | /* Do not display AnchorJS icon on less than 768px view point */ 188 | .anchorjs-link { 189 | display: none; 190 | } 191 | } 192 | 193 | *:hover > .anchorjs-link { 194 | opacity: .75; 195 | /* To fade links as they appear, change transition-property from 'color' to 'all' */ 196 | -webkit-transition: color .16s linear; 197 | transition: color .16s linear; 198 | } 199 | 200 | *:hover > .anchorjs-link:hover, 201 | .anchorjs-link:focus { 202 | text-decoration: none !important; /* do not underline */ 203 | opacity: 1; 204 | } 205 | 206 | .post { 207 | padding: 3rem 0; 208 | font-size: 20px; 209 | font-style: normal; 210 | letter-spacing: -.002em; 211 | word-wrap: break-word; 212 | font-weight: 400; 213 | font-style: normal; 214 | font-size: 21px; 215 | line-height: 1.58; 216 | letter-spacing: -.003em; 217 | color: rgba(0,0,0,.84); 218 | display: inline-block; 219 | margin: auto; 220 | /** margin-left: 20%; **/ 221 | /** width: 70%; **/ 222 | /** min-width: 700px; **/ 223 | display: inline; 224 | } 225 | 226 | .char { 227 | font-size: 19px !important; 228 | line-height: 1.58 !important; 229 | letter-spacing: -.003em !important; 230 | } 231 | 232 | .post-info { 233 | /** color: #aaa; **/ 234 | color: #202124; 235 | /** font-family: Palatino,"Palatino LT STD","Palatino Linotype","Book Antiqua","Georgia",serif; **/ 236 | letter-spacing: 0.5px; 237 | text-align: left; 238 | font-size: 16px; 239 | /** margin-left: 50%; **/ 240 | margin-left: -24em; 241 | float: left; 242 | /** width: 24em; **/ 243 | /** position: fixed; **/ 244 | } 245 | 246 | .post-toc { 247 | /** color: #aaa; **/ 248 | color: #202124; 249 | /** font-family: Palatino,"Palatino LT STD","Palatino Linotype","Book Antiqua","Georgia",serif; **/ 250 | letter-spacing: 0.5px; 251 | text-align: left; 252 | font-size: 16px; 253 | margin-left: 40%; 254 | padding-left: 6em; 255 | /** float: right; **/ 256 | /** width: 24em; **/ 257 | position: fixed; 258 | } 259 | 260 | .post-date { 261 | color: #757575; 262 | font-size: 14px; 263 | } 264 | 265 | .post-info span { 266 | font-style: italic; 267 | } 268 | 269 | .post-title { 270 | color: #202124; 271 | /** font-family: "Helvetica Neue","Segoe UI",Helvetica,Arial,sans-serif; **/ 272 | font-size: 3rem; 273 | margin: 1rem 0; 274 | text-align: left; 275 | /** margin-left: 8em; **/ 276 | margin-bottom: 1em; 277 | } 278 | 279 | .post-line { 280 | border-top: 0.4rem solid #353535; 281 | display: block; 282 | margin: 0 auto 3rem; 283 | width: 4rem; 284 | } 285 | 286 | .post-body { 287 | line-height: 1.58; 288 | letter-spacing: -.003em; 289 | font-size: 16px; 290 | font-weight: 400; 291 | font-style: normal; 292 | /** margin-left: 24em; **/ 293 | /** width: 50em; **/ 294 | float: left; 295 | margin-top: -12px; 296 | } 297 | 298 | .highlight { 299 | background-color: #f9f9f9 !important; 300 | border-radius: 3px; 301 | line-height: 1.4; 302 | margin: 0 0 1rem; 303 | padding: 1rem; 304 | font-size: 0.9em; 305 | } 306 | 307 | blockquote { 308 | border-left: 0.25rem solid #e5e5e5; 309 | color: #979797; 310 | margin: .8rem 0; 311 | padding: 0rem 1rem; 312 | line-height: 1em; 313 | } 314 | 315 | .pagination { 316 | max-width: 700px; 317 | margin: 0 auto; 318 | } 319 | 320 | .doc { 321 | /** max-width: unset !important; **/ 322 | /** padding: unset !important; **/ 323 | width: 40%; 324 | margin: 0 auto; 325 | padding-top: 2em; 326 | padding-bottom: 4em; 327 | } 328 | 329 | code { 330 | white-space: pre-wrap; 331 | } 332 | 333 | .highlight { 334 | margin: 0; 335 | padding: 0.5em; 336 | } 337 | 338 | .catalogue-title { 339 | line-height: 1.18182; 340 | font-size: 44px; 341 | letter-spacing: -.5px; 342 | font-weight: 400; 343 | -webkit-hyphens: auto; 344 | -ms-hyphens: auto; 345 | hyphens: auto; 346 | overflow-wrap: normal; 347 | word-wrap: normal; 348 | -webkit-font-smoothing: antialiased; 349 | text-rendering: optimizeLegibility; 350 | color: #202124; 351 | font-weight: bold; 352 | } 353 | 354 | .catalogue-body { 355 | color: #414141; 356 | line-height: 1.66667; 357 | font-size: 18px; 358 | letter-spacing: 0; 359 | -webkit-font-smoothing: antialiased; 360 | text-rendering: optimizeLegibility; 361 | font-weight: 400; 362 | } 363 | 364 | table, td { 365 | border-spacing: 0; 366 | border-collapse: collapse; 367 | } 368 | 369 | tr { 370 | border-top: 1px solid #c6cbd1; 371 | } 372 | 373 | th { 374 | border: 1px solid #3367d6; 375 | padding: 6px 13px; 376 | background-color: #3367d6; 377 | color: white; 378 | } 379 | 380 | td { 381 | padding: 6px 13px; 382 | border: 1px solid #dfe2e5; 383 | } 384 | 385 | table tr:nth-child(2n) { 386 | background-color: #f6f8fa; 387 | } 388 | 389 | @media only screen and (max-width: 1300px) { 390 | main { 391 | /** padding-top: 6em; **/ 392 | width: unset; 393 | } 394 | .doc { 395 | padding: 1em; 396 | width: unset; 397 | margin: unset; 398 | } 399 | .post { 400 | padding: 0; 401 | margin-left: unset; 402 | } 403 | .post-title, .post-body, .post-info { 404 | margin-left: 0; 405 | margin-bottom: 0; 406 | float: none; 407 | } 408 | .post-body { 409 | width: unset; 410 | } 411 | .post-info { 412 | /** margin-bottom: 2em; **/ 413 | margin-top: 1em; 414 | position: unset; 415 | } 416 | .title { 417 | margin-left: 0; 418 | } 419 | .toc { 420 | display: none; 421 | } 422 | } 423 | 424 | /** 425 | * Create an invisible pseudo-element and make it the height of the 426 | * sticky navbar so the jump takes you to a location above the link 427 | */ 428 | :target::before { 429 | content: ""; 430 | display: block; 431 | margin-top: -80px; 432 | height: 80px; 433 | width: 1px; 434 | } 435 | 436 | a, a:visited, a:hover, a:active { 437 | color: blue; 438 | } 439 | 440 | .toc { 441 | /** position: fixed; **/ 442 | /** left: 3em; **/ 443 | font-size: 14px; 444 | } 445 | 446 | .toc ul { 447 | padding-inline-start: 1em; 448 | list-style-type: none; 449 | } 450 | 451 | .toc > ul { 452 | margin-left: -1em; 453 | } 454 | -------------------------------------------------------------------------------- /explorations/static/mock39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/mock39.gif -------------------------------------------------------------------------------- /explorations/static/mock40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/mock40.gif -------------------------------------------------------------------------------- /explorations/static/mock8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/mock8.png -------------------------------------------------------------------------------- /explorations/static/net-export/fedcm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/fedcm-1.png -------------------------------------------------------------------------------- /explorations/static/net-export/fedcm-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/fedcm-2.png -------------------------------------------------------------------------------- /explorations/static/net-export/net-export-entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/net-export-entry.png -------------------------------------------------------------------------------- /explorations/static/net-export/net-export-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/net-export-stop.png -------------------------------------------------------------------------------- /explorations/static/net-export/netlog-viewer-entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/netlog-viewer-entry.png -------------------------------------------------------------------------------- /explorations/static/net-export/netlog-viewer-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/explorations/static/net-export/netlog-viewer-example.png -------------------------------------------------------------------------------- /explorations/static/rouge.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 25 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 27 | .highlight .m { color: #009999 } /* Literal.Number */ 28 | .highlight .s { color: #d14 } /* Literal.String */ 29 | .highlight .na { color: #008080 } /* Name.Attribute */ 30 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 31 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #008080 } /* Name.Constant */ 33 | .highlight .ni { color: #800080 } /* Name.Entity */ 34 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 35 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 36 | .highlight .nn { color: #555555 } /* Name.Namespace */ 37 | .highlight .nt { color: #000080 } /* Name.Tag */ 38 | .highlight .nv { color: #008080 } /* Name.Variable */ 39 | .highlight .ow { font-weight: bold } /* Operator.Word */ 40 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 41 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 42 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 43 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 44 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 45 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 46 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 47 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 48 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 49 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 50 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 51 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 52 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 53 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 54 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 55 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 56 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 57 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 58 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 59 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 60 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 61 | -------------------------------------------------------------------------------- /explorations/static/rp.html: -------------------------------------------------------------------------------- 1 | Welcome to my website!!! 2 | 3 |
4 | 5 | Click below to sign in to my website! 6 | 7 |
8 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 24 | -------------------------------------------------------------------------------- /meetings/2020/Browsers and Federation - OpenID.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2020/Browsers and Federation - OpenID.pdf -------------------------------------------------------------------------------- /meetings/2020/The Web Platform, Privacy and Federation - IIW.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2020/The Web Platform, Privacy and Federation - IIW.pdf -------------------------------------------------------------------------------- /meetings/2020/The Web Platform, Privacy and Federation - TPAC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2020/The Web Platform, Privacy and Federation - TPAC.pdf -------------------------------------------------------------------------------- /meetings/2021/2021.05.25 - Identity Workshop - Microsoft Edge.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/2021.05.25 - Identity Workshop - Microsoft Edge.pdf -------------------------------------------------------------------------------- /meetings/2021/25-26_May_2021.md: -------------------------------------------------------------------------------- 1 | # Federation and Browsers Workshop, 25-26 May 2021 2 | 3 | **Table of Contents** 4 | 5 | - [Date/Time](#date-time) 6 | * [Day One](#day-one) 7 | * [Day Two](#day-two) 8 | - [Logistics](#logistics) 9 | * [W3C WICG Membership](#w3c-wicg-membership) 10 | * [Behavior](#behavior) 11 | * [Minutes](#minutes) 12 | * [Zoom Details](#zoom-details) 13 | - [Pre-Reading](#pre-reading) 14 | - [Agenda - Day One](#agenda---day-one) 15 | - [Agenda - Day Two](#agenda---day-two) 16 | 17 | ## Date/Time 18 | 19 | ### Day One 20 | 21 | | Start Time | Day One | Location | 22 | | ------------ | ------ | ------------- | 23 | | 10:00 - 13:00 | 25 Tue | San Francisco | 24 | | 13:00 - 16:00 | 25 Tue | New York | 25 | | 18:00 -21:00 | 25 Tue | London | 26 | | 21:00 - 00:00 | 25 Tue | Dubai | 27 | | 02:00 - 05:00 | 26 Wed | Tokyo | 28 | 29 | ### Day Two 30 | 31 | | Start Time | Day Two | Location | 32 | | ------------ | ------ | ------------- | 33 | | 10:00 - 13:00 | 26 Tue | San Francisco | 34 | | 13:00 - 16:00 | 26 Tue | New York | 35 | | 18:00 - 21:00 | 26 Tue | London | 36 | | 21:00 - 00:00 | 26 Tue | Dubai | 37 | | 02:00 - 05:00 | 27 Wed | Tokyo | 38 | 39 | ## Logistics 40 | ### W3C WICG Membership 41 | Participation in this workshop is limited to W3C WICG members. Joining is free. See . 42 | 43 | ### Slack instance 44 | We will use the W3C Community Slack instance. Please click on [this link](https://join.slack.com/t/w3ccommunity/shared_invite/zt-drq1eer6-MlZgOJOWVAEV1UTp66ywAQ) to join, then add yourself to the #federation channel. 45 | 46 | ### Behavior 47 | This meeting is governed by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 48 | You should also be familiar with the [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20040205/). 49 | 50 | ### Minutes 51 | [Google Doc for taking minutes](https://docs.google.com/document/d/1nZt-bU-9FeoaavSuB6KPC7d3vyKuOhnA5QAd8kTN0z0/edit?usp=sharing) 52 | 53 | ### Zoom Details 54 | Topic: Federation and Browsers Workshop, 25-26 May 2021 55 | 56 | Join Zoom Meeting 57 | 58 | 59 | Meeting ID: 810 5816 3304 60 | Passcode: 051420 61 | One tap mobile 62 | +12532158782,,81058163304#,,,,*051420# US (Tacoma) 63 | +13462487799,,81058163304#,,,,*051420# US (Houston) 64 | 65 | Dial by your location 66 | 67 | +1 253 215 8782 US (Tacoma) 68 | +1 346 248 7799 US (Houston) 69 | +1 669 900 6833 US (San Jose) 70 | +1 301 715 8592 US (Washington DC) 71 | +1 312 626 6799 US (Chicago) 72 | +1 929 205 6099 US (New York) 73 | 74 | Meeting ID: 810 5816 3304 75 | 76 | Passcode: 051420 77 | 78 | Find your local number: https://us02web.zoom.us/u/kx0MAb90W 79 | 80 | Join by Skype for Business 81 | https://us02web.zoom.us/skype/81058163304 82 | 83 | 84 | 85 | ## Pre-Reading 86 | * [Privacy Sandbox](https://www.privacysandbox.com/) 87 | * [FedCM](https://github.com/WICG/FedCM/) 88 | * [WebKit](https://webkit.org/blog/category/privacy/) including Storage Access API, isLoggedIn 89 | * [OIDF Browser Interactions](https://github.com/IDBrowserUseCases/docs) 90 | 91 | ## Voting on Questions to discuss in Day Two 92 | Add your question to Slido and vote on what questions we should try and address on Day Two - 93 | 94 | ## Agenda - Day One 95 | 96 | * Intro to the day (10 min) 97 | 98 | * Problems and Solutions from the Browser Perspective (20min each) 99 | * Mozilla Firefox 100 | * Microsoft Edge 101 | * Google Chrome 102 | 103 | * BREAK (15min) 104 | 105 | * Identity Provider use cases (20min each) 106 | * Microsoft Identity 107 | * Facebook 108 | * Google Sign-in 109 | 110 | * BREAK (10min) 111 | 112 | * Wrap up Day 1 (30min) 113 | * Select questions for Day Two 114 | 115 | 116 | ## Agenda - Day Two 117 | * Recap of Day One and Intro to Day Two (10:00 - 10:10) 118 | 119 | * Discussion 120 | * What Problem are We Trying to Solve? (10:10 - 10:40) 121 | * User Provisioning in a Mediated World (10:40 - 11:00) 122 | * AuthN vs AuthZ (11:00 - 11:15) 123 | * Browsers as Adtech Companies (11:15 – 11:20) 124 | * Legal Considerations (11:20 – 11:30) 125 | 126 | * BREAK (11:30 - 11:45) 127 | 128 | * Continuing the Conversation(s) 129 | * Documenting Scenarios (11:45 – 12:00) 130 | * When, Where, Who? (12:00 – 12:45) 131 | 132 | * Wrap Up (12-45 – 12:55) 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /meetings/2021/BlinkOn 15 -- FedCM.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/BlinkOn 15 -- FedCM.pdf -------------------------------------------------------------------------------- /meetings/2021/FedCM @ TPAC 2021 (1).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/FedCM @ TPAC 2021 (1).pdf -------------------------------------------------------------------------------- /meetings/2021/FedCM_ The Timming Attack Problem (1).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/FedCM_ The Timming Attack Problem (1).pdf -------------------------------------------------------------------------------- /meetings/2021/Federated Credential Management - TPAC 2021.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/Federated Credential Management - TPAC 2021.pdf -------------------------------------------------------------------------------- /meetings/2021/Firefox and Federated Login.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/Firefox and Federated Login.pdf -------------------------------------------------------------------------------- /meetings/2021/Intro - Federation and Browsers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/Intro - Federation and Browsers.pdf -------------------------------------------------------------------------------- /meetings/2021/Web Identity API.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/Web Identity API.pdf -------------------------------------------------------------------------------- /meetings/2021/WebID - BlinkOn 14.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/WebID - BlinkOn 14.pdf -------------------------------------------------------------------------------- /meetings/2021/WebID And the Privacy Sandbox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/WebID And the Privacy Sandbox.pdf -------------------------------------------------------------------------------- /meetings/2021/mozilla-screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/mozilla-screenshot-1.png -------------------------------------------------------------------------------- /meetings/2021/mozilla-screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/mozilla-screenshot-2.png -------------------------------------------------------------------------------- /meetings/2021/poll1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/poll1.png -------------------------------------------------------------------------------- /meetings/2021/poll2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/poll2.png -------------------------------------------------------------------------------- /meetings/2021/poll3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/poll3.png -------------------------------------------------------------------------------- /meetings/2021/poll4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/poll4.png -------------------------------------------------------------------------------- /meetings/2021/poll5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2021/poll5.png -------------------------------------------------------------------------------- /meetings/2022/FedCM @ TPAC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2022/FedCM @ TPAC.pdf -------------------------------------------------------------------------------- /meetings/2022/FedCM BlinkOn 16.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2022/FedCM BlinkOn 16.pdf -------------------------------------------------------------------------------- /meetings/2022/FedCM_ Options for the Timing Attack Problem (8_16_2022).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2022/FedCM_ Options for the Timing Attack Problem (8_16_2022).pdf -------------------------------------------------------------------------------- /meetings/2022/FedCM_ Options for the Timing Attack Problem 2022-08-31.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2022/FedCM_ Options for the Timing Attack Problem 2022-08-31.pdf -------------------------------------------------------------------------------- /meetings/2023/CHAPI-FedCM-CCG-Jan-2023.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c-fedid/FedCM/25b4735dd84f5d5994f3acbb819070e0953e3a46/meetings/2023/CHAPI-FedCM-CCG-Jan-2023.pdf -------------------------------------------------------------------------------- /privacy_security_questionnaire.md: -------------------------------------------------------------------------------- 1 | ### 1. What information does this feature expose, and for what purposes? 2 | In the FedCM API, the user is visiting a relying party (RP) and is presented with a prompt to perform federated sign-in by choosing one of their accounts from an identity provider (IDP). 3 | This API exposes the following information to enable this federated sign-in flow: 4 | the user agent fetches metadata about the RP from the IDP. 5 | The user agent queries this from the IDP for a few reasons: 6 | 7 | * The goal of FedCM is to work without requiring any RP interventions, assuming that the RP has embedded an IDP SDK in its site. Therefore, in these cases, all of the information would come from the IDP. 8 | * The IDP may have legal requirements that it needs to verify the links presented to the user. That said, we have a feature request to allow the RP to provide their own links, at least in certain cases. See w3c-fedid/idp-registration#8 for more details. 9 | 10 | This metadata includes a privacy policy URL and Terms of Service. 11 | This exposes to the IDP that someone is visiting the RP, and is necessary to present these links to the user on the FedCM UI. 12 | However, assuming that the RP has embedded an IDP SDK, this does not let the IDP learn anything new, as the IDP can send itself an uncredentialed fetch. 13 | 14 | The user agent performs a separate credentialed fetch to get a list of user’s accounts from the IDP. 15 | This exposes to the IDP that the given user is visiting some unknown website which uses the FedCM API. 16 | Once the user chooses an account from the list of accounts, the user agent gets a token from the IDP and provides this token to the RP. 17 | This exposes information about the user’s selected IdP and account to the RP. 18 | It is necessary to complete the sign-in process. 19 | Exposing this information serves user needs because it enables them to login to sites using credentials from IDPs which they already have. 20 | This removes the need to create a username and password in the RP, thus making it an easier and more secure user experience. 21 | 22 | We are actively working on alternatives to reduce the information exposed before the user chooses an account. 23 | For instance, we could use a delegation model to prevent the IdP from knowing every time the user uses FedCM with them: see https://github.com/w3c-fedid/FedCM/issues/677 for more details. 24 | In addition, there are timing attacks that the RP and IDP can execute (by using the information in the uncredentialed fetch revealing the RP and the credentialed fetch revealing the user’s IdP accounts above) in order to gain knowledge about the user just based on the credentialed request to the IDP to get the user accounts. 25 | We have mitigated this in a couple of ways: 26 | 27 | * We use the login status API to keep track of when users are logged in to the IdP, avoid fetching accounts if they are not, and always show UI if the IdP claims the user is logged in but they are not. This was solved in w3c-fedid/FedCM#447. 28 | * We are actively working on an alternative model where the API does not need to fetch accounts before the user agrees to linking information between the RP and the IDP. The repository for this is https://github.com/fedidcg/LightweightFedCM. 29 | 30 | ### 2. Do features in your specification expose the minimum amount of information necessary to implement the intended functionality? 31 | In order to enable logging in, the browser must request the user accounts from the IDP, and it must provide the ID tokens to the RP once the user chooses an account. 32 | The information exposed includes an account ID, the user’s name, email, and profile picture (and this may be expanded in the future as well). 33 | This information is requested by the browser to create a user-comprehensible dialog. 34 | The information sent to the RP to create the user account is controlled by the IdP, and it is only sent once the user agrees to use the IdP account. 35 | The ID of the account is sent to the IdP to know which account the user has selected. 36 | It is possible to think of a future where the IdP is blind so that either (a) it does not know anything until the user agrees to use the API or (b) it does not know who the RP is even after the exchange of information occurs. 37 | As mentioned above, these are future iterations of the API that we are working on. 38 | 39 | ### 3. Do the features in your specification expose personal information, personally-identifiable information (PII), or information derived from either? 40 | PII is only exposed to the RP once the user consents to login. 41 | The actual information exposed once user consents to login is up to the IdP, and it is not something that this API can control. 42 | 43 | ### 4. How do the features in your specification deal with sensitive information? 44 | The user agent facilitates communication, but it is the IDP who crafts the ID token exposed to the RP for login. 45 | The purpose of this API is to allow federated login, and as such it is necessary to expose the sensitive user information to JavaScript once the user has consented. 46 | It is worth noting that this information does not include any passwords. 47 | This API protects the user’s privacy before consent by not sharing any data with the RP before consent. 48 | 49 | ### 5. Does data exposed by your specification carry related but distinct information that may not be obvious to users? 50 | No 51 | 52 | ### 6. Do the features in your specification introduce state that persists across browsing sessions? 53 | Yes. There is intentionally a new state: the connected accounts set, which stores information about which RP, IDP, accountIDs have been used via FedCM. 54 | This allows the origin to identify the user across multiple page visits, but only because the user has consented to login to this RP via the IDP credentials. 55 | The RP can achieve the same result by just storing a cookie with this information. 56 | The IDP would not receive any information when repeat visits occur, unless the RP requests a new ID assertion (via a navigator.credentials.get request) for whatever reason. 57 | The user should have the ability to logout of the RP as well and even clear the credentials that are created from FedCM. 58 | Thus we believe that browsers consider how clearing Cookies and site data should affect FedCM, when implementing the API. 59 | At a minimum, clearing site data should clear FedCM’s connected accounts set. 60 | In addition, the browser should consider adding FedCM-specific site clearing settings. 61 | Another state introduced with this API is the IDP login status. 62 | This state is used to ensure that fetching accounts always results in some visible UI being shown to the user. 63 | The state is not something that neither the RP nor the IDP can query. 64 | 65 | ### 7. Do the features in your specification expose information about the underlying platform to origins? 66 | No 67 | 68 | ### 8. Does this specification allow an origin to send data to the underlying platform? 69 | No 70 | 71 | ### 9. Do features in this specification enable access to device sensors? 72 | No 73 | 74 | ### 10. Do features in this specification enable new script execution/loading mechanisms? 75 | No 76 | 77 | ### 11. Do features in this specification allow an origin to access other devices? 78 | No 79 | 80 | ### 12. Do features in this specification allow an origin some measure of control over a user agent’s native UI? 81 | Yes. This feature allows the introduction of a sign-in sheet created by the user agent based on the information provided by the IDP. 82 | The user’s choice on the sign in sheet may or may not block other user agent UI: this choice is up to the user agent. 83 | And the user selections on the sheet (other than clicking on the privacy policy or terms of service links) are not redirected to the website, but rather handled directly by the user agent. 84 | 85 | ### 13. What temporary identifiers do the features in this specification create or expose to the web? 86 | The tokens created and used by the FedCM API are managed by the IDP, and hence it is the IDP that has to choose token expiry. 87 | The user agent does not store tokens, and the RP should coordinate with the IDP to refresh tokens as needed. 88 | 89 | ### 14. How does this specification distinguish between behavior in first-party and third-party contexts? 90 | The FedCM API can be called by a top-level frame without issue. 91 | Due to the risk of abuse from giving cross-origin iframes access to the API, by default these cannot access the API. 92 | However, there are use-cases for requesting users to sign in from an iframe. 93 | We use Permissions Policy to allow top-level frames to grant iframes with permissions for calling the API. 94 | 95 | ### 15. How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode? 96 | The FedCM API should work the same way in Incognito mode, thus not introducing a way for the RP to tell that the user is currently browsing in that mode. 97 | In addition, as with cookies, any state resulting from browsing in incognito mode should be cleared once the user ends the session. 98 | 99 | ### 16. Does this specification have both "Security Considerations" and "Privacy Considerations" sections? 100 | Security section: https://w3c-fedid.github.io/FedCM/#security 101 | 102 | Privacy section: https://w3c-fedid.github.io/FedCM#privacy 103 | 104 | ### 17. Do features in your specification enable origins to downgrade default security protections? 105 | No. This API allows the RP and IDP to communicate with each other to enable federated login in the absence of third-party cookies. 106 | The specification will allow the usage of Permissions Policy to enable the API on iframes, so in particular this API is disabled by default on iframes. 107 | 108 | ### 18. What happens when a document that uses your feature is kept alive in BFCache (instead of getting destroyed) after navigation, and potentially gets reused on future navigations back to the document? 109 | The dialog to choose an IDP and a user account within the IDP should not be shown when the document is not visible, which in particular means that it should not be shown for non-fully active documents. 110 | So in particular a FedCM request should be dismissed once the document enters the BFCache, and the document may resurface a request after 111 | 112 | ### 19. What happens when a document that uses your feature gets disconnected? 113 | The FedCM request associated with a disconnected document should be rejected and any UI being shown dismissed. 114 | 115 | ### 20. Does your spec define when and how new kinds of errors should be raised? 116 | Our spec does not use new kinds of errors, but rather existing ones 117 | 118 | ### 21. Does your feature allow sites to learn about the user’s use of assistive technology? 119 | No 120 | 121 | ### 22. What should this questionnaire have asked? 122 | Timing attacks were discussed briefly in 2.1. 123 | It could be useful to ask whether there are multiple bits of information that are disclosed separately but when correlated help break privacy or security assumptions. 124 | -------------------------------------------------------------------------------- /spec/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all spec idl clean 2 | 3 | all: spec idl 4 | 5 | spec: index.html 6 | 7 | idl: fedcm.idl 8 | 9 | fedcm.idl: index.bs 10 | ./extract_idl.rb fedcm.idl 11 | 12 | index.html: index.bs 13 | bikeshed --die-on=fatal spec index.bs 14 | 15 | clean: 16 | rm index.html 17 | rm fedcm.idl 18 | -------------------------------------------------------------------------------- /spec/extract_idl.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'date' 4 | 5 | if ARGV.length < 1 6 | puts "Filename required" 7 | exit 2 8 | end 9 | 10 | outfile = ARGV[0] 11 | 12 | YEAR=DateTime.now.year 13 | HEADER=</ 38 | f.puts 39 | in_idl = false 40 | else 41 | f.puts l 42 | end 43 | elsif l =~ /xmp class="?idl/ 44 | in_idl = true 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": "wg/fedid" 3 | , "contacts": ["simoneonofri", "hlflanagan", "wseltzer"] 4 | , "repo-type": "rec-track" 5 | } 6 | --------------------------------------------------------------------------------