├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── common.js └── index.html /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # they will be requested for review when someone opens a 4 | # pull request. 5 | * @dlongley 6 | 7 | # See CODEOWNERS syntax here: https://help.github.com/articles/about-codeowners/#codeowners-syntax 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # W3C Credentials Community Group 2 | 3 | Contributions to this repository are intended to become part of 4 | Recommendation-track documents governed by the 5 | [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20040205/) and 6 | [Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software). 7 | To make substantive contributions to specifications, you must either participate 8 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 9 | 10 | If you are not the sole contributor to a contribution (pull request), please 11 | identify all contributors in the pull request comment. 12 | 13 | To add a contributor (other than yourself, that's automatic), mark them one 14 | per line as follows: 15 | 16 | ``` 17 | +@github_username 18 | ``` 19 | 20 | If you added a contributor by mistake, you can remove them in a comment with: 21 | 22 | ``` 23 | -@github_username 24 | ``` 25 | 26 | If you are making a pull request on behalf of someone else but you had no 27 | part in designing the feature, you can remove yourself with the above syntax. 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors under the [W3C Software and Document 2 | License](https://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 Software, including sample implementations, are under the 8 | [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # credential-handler-api 2 | Repository for the Credential Handler specification of the Credentials Community Group 3 | 4 | ## Background 5 | 6 | A Credential Handler is an event handler for credential request and 7 | credential storage events. The [Credential Handler API][] helps 8 | solve the [Nascar Problem](https://indieweb.org/NASCAR_problem). The 9 | [Credential Handler API][] enables websites to install Credential Handlers that 10 | can respond when users visit other websites that request or store credentials. 11 | 12 | For example, a user may visit a website that wants them to login using 13 | OpenIDConnect, provide an OAuth Token, authenticate using a [DID][], or present 14 | some [Verifiable Credential][]. When these other websites use the [Credential 15 | Handler API][], the user is shown an in-browser selection screen with visual 16 | representations (e.g., icons and/or origin information) of only those 17 | Credential Handlers which have been previously installed by the user and 18 | that are compatible with the website's request. Once the user makes a choice, 19 | the appropriate Credential Handler is loaded, and a credential event is sent 20 | to it. 21 | 22 | The Credential Handler receives the event via a 23 | [Service Worker](https://w3c.github.io/ServiceWorker), or, if the 24 | [Credential Handler Polyfill][] is used, a simple page with no UI elements is 25 | loaded, and it uses the polyfill to receive and respond to the event. 26 | 27 | The Credential Handler must respond to the event with a credential that 28 | fulfills the request. If necessary, the Credential Handler may open a window 29 | on its website's origin to allow the user to interact with its website prior 30 | to responding. This UI can be styled and shaped according to the website 31 | owner's brand using arbitrary JavaScript and HTML like any other webpage. 32 | 33 | ## Demo 34 | 35 | ***We provide a demo of this potential future Web feature below. Please note that the demo uses a polyfill that provides UI that emulates secure browser chrome. To repeat, this polyfill UI is an emulation and IS NOT actually implemented by the browser. Support for this API could make this UI (or most likely a much better one!) a reality in browsers in the future.*** 36 | 37 | The demo of the credential handler in action is here: 38 | 39 | 1. [Demo Wallet](https://wallet.example.chapi.io/) 40 | 2. [Demo Issuer](https://issuer.example.chapi.io/) 41 | 3. [Demo Verifier](https://verifier.example.chapi.io/) 42 | 43 | Please see the [polyfill README][] for animated GIFs of the polyfill and 44 | demo in action. 45 | 46 | The demo sites work in Chrome, Firefox, Edge, and the most recent versions of 47 | Safari/iOS. (Safari must have support for the Storage Access API.) 48 | 49 | The Storage Access API is required in Safari because the Credential Handler 50 | polyfill uses a neutral, shared, third-party website to store the credential handler 51 | registrations users create. These are not the credentials themselves, but a 52 | registration list of the credential handler(s) (i.e., digital wallet 53 | URLs) that you have previously registered. Storage of this registration list 54 | enables the browser to show the user a selector UI with the registered digital wallets that could 55 | possibly fulfill a request for credentials from a relying party website. 56 | 57 | Prior to implementing the Storage Access API, Safari partitioned its 58 | third-party storage and cookies such that the polyfill could not function 59 | without the user manually changing settings in the browser. 60 | 61 | ## Explainer 62 | 63 | ## Roles 64 | 65 | The Credential Handler API's design is such that there are four roles that are 66 | played when passing credentials over the Web: 67 | 68 | ### Credential Repository 69 | 70 | This role handles credential storage and requests for a user, acting as their 71 | "wallet". This role is responsible for providing a "Credential Handler". 72 | This role is implemented as Web App on a credential wallet website. 73 | 74 | ### Credential Issuer 75 | 76 | This role issues credentials to a user for them to put in a wallet. 77 | 78 | ### Credential Verifier 79 | 80 | This role requests credentials from a user. Users fulfill this request via a 81 | wallet of the user's choice. 82 | 83 | ### Mediator 84 | 85 | This role mediates all credential storage and credential requests for a user. 86 | It is responsible for helping the user make wallet choices and proxying 87 | requests and responses to/from relying party websites (credential issuers and 88 | credential verifiers) and the user's chosen wallet. This role is played by the 89 | user agent (browser). 90 | 91 | ## Typical Flow 92 | 93 | 1. A user visits a "credential wallet" website. 94 | 95 | 2. The wallet web app registers a "Credential Handler". 96 | 97 | During this step, the web app calls a new JavaScript API to register a piece of 98 | code (a "Credential Handler") that will execute when the user later elects to 99 | use the web app to fulfill a request for credentials or a request to store 100 | credentials. 101 | 102 | 3. The user visits a Credential Issuer website to receive a credential. 103 | 104 | The Credential Issuer website calls the Credential Management API to store a 105 | new type of Web-based credential (i.e., essentially a third-party credential, or 106 | a credential that may be used across domains). 107 | 108 | 4. The browser shows the user a UI with information (such as icons, text, or origins) 109 | representing previously registered credential handlers that can store their 110 | new credential. 111 | 112 | When the user makes a selection, the credential to be stored is forwarded to 113 | the chosen handler, which then allows the user to interact with the associated 114 | Web App from the wallet origin as needed to complete the storage request. 115 | 116 | The browser is playing the "Mediator" role here: forwarding a request from the 117 | Credential Issuer to a third-party Credential Repository of the user's choice. 118 | The Credential Issuer doesn't care which wallet is used. All the mediator needs 119 | to do is match up credential storage requests with wallets that 120 | support their storage, and present these options to the user. 121 | 122 | 5. The user visits a Credential Verifier website which requests third-party 123 | (Web-based) credentials. 124 | 125 | Here the Credential Verifier website calls the Credential Management API using 126 | a query for a new type of Web-based credential (i.e., essentially a third-party 127 | credential, or a credential that may be used across domains). 128 | 129 | 6. The browser shows the user a UI with information (icons, text, origins) 130 | representing previously registered credential handlers. 131 | 132 | When the user makes a selection, the Credential Verifier's request is forwarded 133 | to the chosen credential handler. 134 | 135 | The browser is playing the "Mediator" role here: forwarding a request from the 136 | Credential Verifier to a third-party Credential Repository of the user's 137 | choice. The Credential Verifier doesn't care which wallet is used; they have 138 | a trust relationship with Credential Issuers, not the wallet provider. All the 139 | mediator needs to do is match up requests for credentials to the 140 | user's preferred wallet(s) for fulfilling those requests. 141 | 142 | 7. The user interacts as needed with the wallet Web App, and chooses the 143 | credentials to fulfill the request. 144 | 145 | Here the Web App resolves a Promise with the user's response. If required 146 | by the specific Web credential scheme/protocol, the response 147 | may include additional authentication information to prove 148 | ownership over the credentials. 149 | 150 | 8. The browser forwards the credential response to the Credential Verifier. 151 | 152 | 9. The Credential Verifier verifies the credentials, and proceeds however 153 | it sees fit. 154 | 155 | This flow works for DID-Auth, passing Verifiable Credentials, or using other 156 | systems such as OpenID Connect (OIDC). 157 | 158 | ## IANA Considerations 159 | 160 | The following section should be submitted to the Internet Engineering Steering 161 | Group (IESG) for review, approval, and registration with IANA. 162 | 163 | #### `application/credentialquery+json` 164 | 165 |
166 |
Type name:
167 |
application
168 | 169 |
Subtype name:
170 |
credentialquery+json
171 | 172 |
Required parameters:
173 |
None
174 | 175 |
Encoding consideration:
176 |
TBD
177 | 178 |
Security considerations:
179 |
TBD
180 | 181 |
Interoperability considerations:
182 |
TBD
183 | 184 |
Published specification:
185 |
https://w3c-ccg.github.io/credential-handler-api
186 | 187 |
Applications that use this media type:
188 |
TBD
189 |
190 | 191 | 192 | 193 | --- 194 | 195 | TODO: Links to DID-Auth, Verifiable Credentials, and OpenIDConnect 196 | 197 | TODO: Diagrams of the roles and data flows 198 | 199 | [DID]: https://w3c.github.io/did 200 | [Verifiable Credentials]: https://w3c.github.io/vc-data-model 201 | [Decentralized Identifiers (DIDs)]: https://w3c.github.io/did 202 | [Credential Handler API]: https://w3c-ccg.github.io/credential-handler-api 203 | [Credential Handler API Repo]: https://github.com/w3c-ccg/credential-handler-api 204 | [Credential Handler Polyfill]: https://github.com/credential-handler/credential-handler-polyfill 205 | [Credential Handler Wallet Demo Repo]: https://github.com/credential-handler/chapi-demo-wallet 206 | [Credential Handler Issuer Demo Repo]: https://github.com/credential-handler/chapi-demo-issuer 207 | [Credential Handler Verifier Demo Repo]: https://github.com/credential-handler/chapi-demo-verifier 208 | [polyfill README]: https://github.com/credential-handler/credential-handler-polyfill#credential-handler-api-polyfill-credential-handler-polyfill 209 | -------------------------------------------------------------------------------- /common.js: -------------------------------------------------------------------------------- 1 | /* globals omitTerms, respecConfig, $, require */ 2 | /* exported linkCrossReferences, restrictReferences, fixIncludes */ 3 | 4 | var vcwg = { 5 | // Add as the respecConfig localBiblio variable 6 | // Extend or override global respec references 7 | localBiblio: { 8 | "REST": { 9 | title: "Architectural Styles and the Design of Network-based Software Architectures", 10 | date: "2000", 11 | href: "http://www.ics.uci.edu/~fielding/pubs/dissertation/", 12 | authors: [ 13 | "Fielding, Roy Thomas" 14 | ], 15 | publisher: "University of California, Irvine." 16 | }, 17 | "VC-USECASES": { 18 | title: "Verifiable Claims Use Cases", 19 | href: "https://www.w3.org/TR/verifiable-claims-use-cases/", 20 | authors: [ 21 | "Shane McCarron", 22 | "Daniel Burnett", 23 | "Gregg Kellogg", 24 | "Brian Sletten", 25 | "Manu Sporny" 26 | ], 27 | status: "FPWD", 28 | publisher: "Verifiable Claims Working Group" 29 | }, 30 | // aliases to known references 31 | "HTTP-SIGNATURES": { 32 | aliasOf: "http-signatures" 33 | }, 34 | "MACAROONS": { 35 | title: 'Macaroons', 36 | // TODO: create spec 37 | href: 'http://macaroons.io/', 38 | authors: ['Arnar Birgisson', 'Joe Gibbs Politz', 'Úlfar Erlingsson', 39 | 'Ankur Taly', 'Michael Vrable', 'Mark Lentczner'], 40 | status: 'unofficial', 41 | publisher: 'Credentials Community Group' 42 | }, 43 | 'OPEN-BADGES': { 44 | title: 'Open Badges', 45 | href: 'https://github.com/openbadges/openbadges-specification', 46 | authors: ['Brian Brennan', 'Mike Larsson', 'Chris McAvoy', 47 | 'Nate Otto', 'Kerri Lemoie'], 48 | status: 'BA-DRAFT', 49 | publisher: 'Badge Alliance Standard Working Group' 50 | }, 51 | 'RDF-NORMALIZATION': { 52 | title: 'RDF Dataset Normalization', 53 | href: 'http://json-ld.github.io/normalization/spec/', 54 | authors: ['Dave Longley', 'Manu Sporny'], 55 | status: 'CG-DRAFT', 56 | publisher: 'Credentials W3C Community Group' 57 | }, 58 | } 59 | }; 60 | 61 | 62 | 63 | // We should be able to remove terms that are not actually 64 | // referenced from the common definitions 65 | // 66 | // the termlist is in a block of class "termlist", so make sure that 67 | // has an ID and put that ID into the termLists array so we can 68 | // interrogate all of the included termlists later. 69 | var termNames = [] ; 70 | var termLists = [] ; 71 | var termsReferencedByTerms = [] ; 72 | 73 | function restrictReferences(utils, content) { 74 | "use strict"; 75 | var base = document.createElement("div"); 76 | base.innerHTML = content; 77 | 78 | // New new logic: 79 | // 80 | // 1. build a list of all term-internal references 81 | // 2. When ready to process, for each reference INTO the terms, 82 | // remove any terms they reference from the termNames array too. 83 | $.each(base.querySelectorAll("dfn"), function(i, item) { 84 | var $t = $(item) ; 85 | var titles = $t.getDfnTitles(); 86 | var dropit = false; 87 | // do we have an omitTerms 88 | if (window.hasOwnProperty("omitTerms")) { 89 | // search for a match 90 | $.each(omitTerms, function(j, term) { 91 | if (titles.indexOf(term) !== -1) { 92 | dropit = true; 93 | } 94 | }); 95 | } 96 | // do we have an includeTerms 97 | if (window.hasOwnProperty("includeTerms")) { 98 | var found = false; 99 | // search for a match 100 | $.each(includeTerms, function(j, term) { 101 | if (titles.indexOf(term) !== -1) { 102 | found = true; 103 | } 104 | }); 105 | if (!found) { 106 | dropit = true; 107 | } 108 | } 109 | if (dropit) { 110 | $t.parent().next().remove(); 111 | $t.parent().remove(); 112 | } else { 113 | var n = $t.makeID("dfn", titles[0]); 114 | if (n) { 115 | termNames[n] = $t.parent() ; 116 | } 117 | } 118 | }); 119 | 120 | var $container = $(".termlist",base) ; 121 | var containerID = $container.makeID("", "terms") ; 122 | termLists.push(containerID) ; 123 | 124 | return (base.innerHTML); 125 | } 126 | // add a handler to come in after all the definitions are resolved 127 | // 128 | // New logic: If the reference is within a 'dl' element of 129 | // class 'termlist', and if the target of that reference is 130 | // also within a 'dl' element of class 'termlist', then 131 | // consider it an internal reference and ignore it. 132 | 133 | require(["core/pubsubhub"], function(respecEvents) { 134 | "use strict"; 135 | respecEvents.sub('end', function(message) { 136 | if (message === 'core/link-to-dfn') { 137 | // all definitions are linked; find any internal references 138 | $(".termlist a.internalDFN").each(function() { 139 | var $r = $(this); 140 | var id = $r.attr('href'); 141 | var idref = id.replace(/^#/,"") ; 142 | if (termNames[idref]) { 143 | // this is a reference to another term 144 | // what is the idref of THIS term? 145 | var $def = $r.closest('dd') ; 146 | if ($def.length) { 147 | var $p = $def.prev('dt').find('dfn') ; 148 | var tid = $p.attr('id') ; 149 | if (tid) { 150 | if (termsReferencedByTerms[tid]) { 151 | termsReferencedByTerms[tid].push(idref); 152 | } else { 153 | termsReferencedByTerms[tid] = [] ; 154 | termsReferencedByTerms[tid].push(idref); 155 | } 156 | } 157 | } 158 | } 159 | }) ; 160 | 161 | // clearRefs is recursive. Walk down the tree of 162 | // references to ensure that all references are resolved. 163 | var clearRefs = function(theTerm) { 164 | if ( termsReferencedByTerms[theTerm] ) { 165 | $.each(termsReferencedByTerms[theTerm], function(i, item) { 166 | if (termNames[item]) { 167 | delete termNames[item]; 168 | clearRefs(item); 169 | } 170 | }); 171 | } 172 | // make sure this term doesn't get removed 173 | if (termNames[theTerm]) { 174 | delete termNames[theTerm]; 175 | } 176 | }; 177 | 178 | // now termsReferencedByTerms has ALL terms that 179 | // reference other terms, and a list of the 180 | // terms that they reference 181 | $("a.internalDFN").each(function () { 182 | var $item = $(this) ; 183 | var t = $item.attr('href'); 184 | var r = t.replace(/^#/,"") ; 185 | // if the item is outside the term list 186 | if ( ! $item.closest('dl.termlist').length ) { 187 | clearRefs(r); 188 | } 189 | }); 190 | 191 | // delete any terms that were not referenced. 192 | Object.keys(termNames).forEach(function(term) { 193 | var $p = $("#"+term) ; 194 | if ($p) { 195 | var tList = $p.getDfnTitles(); 196 | $p.parent().next().remove(); 197 | $p.parent().remove() ; 198 | tList.forEach(function( item ) { 199 | if (respecConfig.definitionMap[item]) { 200 | delete respecConfig.definitionMap[item]; 201 | } 202 | }); 203 | } 204 | }); 205 | } 206 | }); 207 | }); 208 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Credential Handler API 1.0 6 | 7 | 8 | 10 | 11 | 12 | 51 | 59 | 60 | 61 |
62 |

63 | Credential Management Level 1 64 | describes an imperative API enabling a website to request a user’s 65 | credentials from a user agent, and to help the user agent correctly 66 | store user credentials for future use. User agents implementing that 67 | API prompt the user to select a way to handle a credential request, 68 | after which the user agent returns a credential to the originating 69 | site. This specification defines capabilities that enable third-party 70 | Web applications to handle credential requests and storage. 71 |

72 |
73 |
74 |

75 | The Credentials Community Group maintains a list of 77 | all bug reports that the group has not yet addressed. This draft 78 | highlights some of the pending issues that are still to be discussed 79 | in the community group. No decision has been taken on the outcome of 80 | these issues including whether they are valid. Pull requests with 81 | proposed specification text for outstanding issues are strongly 82 | encouraged. 83 |

84 |
85 |
86 |

87 | Introduction 88 |

89 |

90 | The mission of the Credentials Community Group is to explore the 91 | creation, storage, presentation, verification, and user control of 92 | credentials. Its focus is placed on a verifiable credential (a set of 93 | claims) created by an issuer about a subject: a person, group, or 94 | thing. It seeks solutions inclusive of approaches such as: 95 | self-sovereign identity; presentation of proofs by the bearer; data 96 | minimization; and centralized, federated, and decentralized registry and 97 | identity systems. Therefore, the Credentials Community Group presents 98 | a specification that extends the 99 | Credential Management Level 1 100 | API to allow users to designate trusted third party Web applications 101 | as handlers for credential requests and credential storage. 102 |

103 |

104 | A credential repository is a Web application that can 105 | handle credential requests and credential storage on behalf of the 106 | user. This specification defines a number of new Web platform features 107 | to handle credential requests and credential storage: 108 |

109 | 129 |

130 | This specification does not address how software built with 131 | operating-system specific mechanisms (e.g., "native mobile apps") 132 | handle credential requests and credential storage. 133 |

134 |
135 |
136 |

137 | This specification defines one class of products: 138 |

139 |
140 |
141 | Conforming user agent 142 |
143 |
144 |

145 | A user agent MUST behave as described in this specification 146 | to be considered conformant. In this specification, user 147 | agent means a Web browser or other interactive user 148 | agent as defined in [[!HTML5]]. 149 |

150 |

151 | User agents MAY implement algorithms given in this specification in 152 | any way desired, so long as the end result is indistinguishable 153 | from the result that would be obtained by the specification's 154 | algorithms. 155 |

156 |

157 | A conforming Credential Handler API user agent MUST also be a 158 | conforming implementation of the IDL fragments of this 159 | specification, as described in the “Web IDL” specification. 160 | [[!WEBIDL-LS]] 161 |

162 | 166 |
167 |
168 |
169 |
170 |

171 | Overview of Handling Credential Request and Storage 172 |

173 |

174 | In this document we envision the following flow for a credential 175 | request: 176 |

177 |
    178 |
  1. An origin requests permission from the user to handle credential 179 | request and storage for a set of supported credential types. For 180 | example, a user visiting a digital wallet provider site may be prompted 181 | to register a credential handler from that origin. The origin 182 | establishes the scope of the permission but the origin's capabilities 183 | may evolve without requiring additional user consent. 184 |
  2. 185 |
  3. 186 | Credential handlers are defined in service worker code. 187 |
  4. 188 |
  5. During service worker registration, the CredentialManager is 189 | used to set: 190 |
      191 |
    • A list of enabled 192 | WebCredential types. 193 |
    • 194 |
    • [Optionally] the conditions under which the handler supports a 195 | given WebCredential type; these match play a role in matching 197 | computations. 198 |
    • 199 |
    • Information used in the display of hints supported by the 201 | credential handler. 202 |
    • 203 |
    204 |
  6. 205 |
  7. There are two entry points for interaction with a credential 206 | handler: when a relying party (aka verifier) calls the 207 | [[credential-management-1]] method get() (e.g., when the user 208 | pushes a button on a page that requires identity attributes or 209 | authentication) with WebCredentialRequestOptions and 210 | when an issuer calls the [[credential-management-1]] method 211 | store() (e.g., when the user pushes a button to receive a 212 | credential) with a WebCredential. In both of these cases, the 213 | user agent computes a list of candidate credential hints, comparing 214 | the WebCredential types accepted by the relying party with those 215 | supported by registered credential handlers. For WebCredential types 216 | that support additional filtering, the relying party's specific request 217 | and the match information from each credential hint is compared as part 218 | of determining whether there is compatibility. 219 |
  8. 220 |
  9. The user agent displays a set of choices to the user: the 221 | registered hints of 222 | the candidate credential handlers. The user agent displays these choices 223 | using information (labels and icons) provided at registration or 224 | otherwise available from the Web app. 225 |
  10. 226 |
  11. When the user selects a hint, the user agent 228 | fires a CredentialRequestEvent (cf. the user 229 | interaction task source) or a CredentialStoreEvent (depending 230 | on the method called) in the service worker whose CredentialManager the 232 | hint was registered with. The CredentialRequestEvent includes 233 | the CredentialRequestOptions (defined in [[!credential-management-1]]), 234 | including credential-type-specific options, as well as additional 235 | information (e.g., origin and selected hint). 236 |
  12. 237 |
  13. Once activated, the credential handler performs whatever steps are 238 | necessary to handle the 239 | credential request or 240 | handle credential storage, 241 | and return an appropriate WebCredential to the relying party or issuer. 242 | If interaction with the user is necessary, the credential handler 243 | can open a context-specific window for that purpose. 244 |
  14. 245 |
  15. The user agent receives a response asynchronously once the 246 | credential handler has finished handling the request. The response 247 | is a WebCredential or null if the request was denied. 248 |
  16. 249 |
250 |

253 | The origin information of the relying party may be blinded when 254 | received via a CredentialRequestEvent. 255 |

256 |

257 | An origin may implement a credential repository with more than one 258 | service worker and therefore multiple credential handlers may 259 | be registered per origin. The handler that is invoked is determined by 260 | the selection made by the user of a 261 | credential hint. The 262 | service worker which stored the credential hint with its 264 | CredentialManager 266 | is the one that will be invoked. 267 |

268 |
269 |

270 | Handling a Credential Request 271 |

272 |

273 | The logic of a credential handler is driven by the WebCredential 274 | types that it supports. Some WebCredential types may require 275 | very little processing on the part of the credential handler other 276 | than retrieving a WebCredential from its storage and returning it 277 | as a response. 278 |

279 |

280 | In contrast, some Web Credential types, such as 281 | VerifiableProfile include a custom query parameter that 282 | must be understood and processed by the credential handler in order 283 | for it to return an appropriate WebCredential in response. This 284 | may involve presenting a user interface to allow the user to make 285 | selections. In some cases, a credential handler may need to generate 286 | a WebCredential dynamically with the assistance of an issuer or 287 | blinding service. It may also need to generate a zero knowledge proof 288 | or use some other privacy enhancing cryptographic method. 289 |

290 |

291 | Therefore, handling a credential request may include numerous 292 | interactions: with the user through a new contextual window or other 293 | APIs (such as [[!WebCryptoAPI]]) or with other services and origins 294 | through web requests or other means. 295 |

296 |

297 | Once a WebCredential is returned to the relying party website, it is 298 | its job to perform whatever verification is appropriate for its type. 299 |

300 |

301 | This specification does not address the activities that occur 302 | between the credential handler accepting the 303 | CredentialRequestEvent and the credential handler returning a 304 | response. All of the activities which may be required to configure 305 | the credential handler and handle the credential request are left to 306 | the implementation of the credential handler, including: 307 |

308 | 319 |

320 | Thus, an origin will rely on many other Web technologies defined 321 | elsewhere for lifecycle management, security, user authentication, 322 | user interaction, and so on. 323 |

324 |
325 |
326 |

327 | Handling Credential Storage 328 |

329 |

330 | The logic of a credential handler is driven by the WebCredential 331 | types that it supports. Some WebCredential types may require 332 | very little processing on the part of the credential handler other 333 | than storing the WebCredential in a database and returning it 334 | as a response. 335 |

336 |

337 | In contrast, some Web Credential types, such as 338 | VerifiableProfile may include multiple sub-credentials whereby 339 | the user may only elect to store some subset of them, through the use 340 | of a user interface provided by the credential handler. 341 |

342 |

343 | Handling credential storage may include numerous interactions: with 344 | the user through a new contextual window or other APIs (such as 345 | [[!WebCryptoAPI]]) or with other services and origins through web 346 | requests or other means. 347 |

348 |

349 | The WebCredential that is returned to the issuer website provides 350 | information on what was stored by the credential handler, enabling 351 | the issuer website to take whatever next actions are appropriate. 352 |

353 |

354 | This specification does not address the activities that occur 355 | between the credential handler accepting the 356 | CredentialStoreEvent and the credential handler returning a 357 | response. All of the activities which may be required to configure 358 | the credential handler and handle credential storage are 359 | left to the implementation of the credential handler, including: 360 |

361 | 372 |

373 | Thus, an origin will rely on many other Web technologies defined 374 | elsewhere for lifecycle management, security, user authentication, 375 | user interaction, and so on. 376 |

377 |
378 |
379 |

380 | Structure of a Web Credential Repository 381 |

382 |
383 | 384 386 |
387 | A Web credential repository is associated with an origin. 388 | Credential handlers respond to CredentialRequestEvents and 389 | CredentialStoreEvents. CredentialManagers 390 | manage the definition, display, and user selection of 391 | CredentialHints. A CredentialHint supports one 392 | or more WebCredential types. 393 |
394 |
395 |
396 |
397 |

398 | Relation to Other Types of Credential Repositories 399 |

400 |

401 | This specification does not address how third-party mobile credential 402 | repository apps interact (through proprietary mechanisms) with user 403 | agents, or how user agents themselves provide simple credential 404 | repository functionality. 405 |

406 |
407 | 408 411 |
412 | Credential Handler API enables Web apps to handle credential 413 | management. Other types of credential repository apps may use other 414 | (proprietary) mechanisms. 415 |
416 |
417 |
418 |
419 |
420 |

421 | Registration 422 |

423 |
425 |

426 | Extension to the ServiceWorkerRegistration interface 427 |

428 |

429 | This specification extends the ServiceWorkerRegistration 430 | interface with the addition of a credentialManager 431 | attribute. 432 |

433 |
 434 |         partial interface ServiceWorkerRegistration {
 435 |           readonly attribute CredentialManager credentialManager;
 436 |         };
 437 |       
438 |
439 |
440 |

441 | CredentialManager interface 442 |

443 |
 444 |       [SecureContext, Exposed=(Window,Worker)]
 445 |       interface CredentialManager {
 446 |         [SameObject] readonly attribute CredentialHints hints;
 447 |         [Exposed=Window] static Promise<PermissionState> requestPermission();
 448 |       };
 449 |       
450 |

451 | The CredentialManager is used by credential repositories 452 | to manage their associated hints and supported WebCredential types. 453 |

454 |
455 |

456 | hints attribute 457 |

458 |

459 | This attribute allows manipulation of credential hints associated 460 | with a service worker (and therefore its credential handler). To be 461 | a candidate credential handler, a handler must have at least one 462 | registered credential hint to present to the user. That instrument 463 | needs to match the WebCredential types and type-specific query 464 | information specified by the credential request. 465 |

466 |
467 |
468 |

469 | requestPermission() method 470 |

471 |

472 | The user agent is NOT REQUIRED to prompt the user to grant 473 | permission to the origin for each new supported WebCredential 474 | type or new credential hint. 475 |

476 |

477 | When called, this method executes the following steps: 478 |

479 |
    480 |
  1. Let p be a new promise. 481 |
  2. 482 |
  3. Return p and perform the remaining steps in 483 | parallel: 484 |
  4. 485 |
  5. Let permission be the result of running 486 | retrieve 487 | the permission state algorithm of the permission associated 488 | with credential handler's origin. 489 |
  6. 490 |
  7. If permission is "prompt", ask the user whether 491 | allowing adding new credential hints for the current settings object's 493 | origin is acceptable. If it is, set permission to 494 | "granted", and "denied" otherwise. 495 |
  8. 496 |
  9. Resolve p with permission. 497 |
  10. 498 |
499 |
500 |
501 |
503 |

504 | CredentialHints interface 505 |

506 |
 507 |       [SecureContext, Exposed=(Window,Worker)]
 508 |       interface CredentialHints {
 509 |           Promise<boolean>           delete(DOMString hintKey);
 510 |           Promise<CredentialHint>    get(DOMString hintKey);
 511 |           Promise<sequence<DOMString>>  keys();
 512 |           Promise<boolean>           has(DOMString hintKey);
 513 |           Promise<void>              set(DOMString hintKey, CredentialHint hint);
 514 |           Promise<void>           clear();
 515 |       };
 516 |       
517 |

518 | The CredentialHints interface represents a collection of 519 | credential hints, each uniquely identified by a hintKey. 520 | The hintKey identifier will be passed to the credential 521 | handler to indicate the CredentialHint selected by the user. A 522 | CredentialHint is associated with a context or aspect of the 523 | user for which they store certain credentials, similar to a digital 524 | version of a physical wallet. 525 |

526 |
527 |

528 | delete() method 529 |

530 |

531 | When called, this method executes the following steps: 532 |

533 |
    534 |
  1. Let p be a new promise. 535 |
  2. 536 |
  3. Return p and perform the remaining steps in 537 | parallel: 538 |
  4. 539 |
  5. If the collection contains a CredentialHint with a 540 | matching hintKey, remove it from the collection 541 | and resolve p with true. 542 |
  6. 543 |
  7. Otherwise, resolve p with false. 544 |
  8. 545 |
546 |
547 |
548 |

549 | get() method 550 |

551 |

552 | When called, this method executes the following steps: 553 |

554 |
    555 |
  1. Let p be a new promise. 556 |
  2. 557 |
  3. Return p and perform the remaining steps in 558 | parallel: 559 |
  4. 560 |
  5. If the collection contains a CredentialHint with a 561 | matching hintKey, resolve p with that 562 | CredentialHint. 563 |
  6. 564 |
  7. Otherwise, reject p with a DOMException whose 565 | value is "NotFoundError". 566 |
  8. 567 |
568 |
569 |
570 |

571 | keys() method 572 |

573 |

574 | When called, this method executes the following steps: 575 |

576 |
    577 |
  1. Let p be a new promise. 578 |
  2. 579 |
  3. Return p and perform the remaining steps in 580 | parallel: 581 |
  4. 582 |
  5. Resolve p with a Sequence that contains 583 | all the hintKeys for the CredentialHints 584 | contained in the collection, in original insertion order. 585 |
  6. 586 |
587 |
588 |
589 |

590 | has() method 591 |

592 |

593 | When called, this method executes the following steps: 594 |

595 |
    596 |
  1. Let p be a new promise. 597 |
  2. 598 |
  3. Return p and perform the remaining steps in 599 | parallel: 600 |
  4. 601 |
  5. If the collection contains a CredentialHint with a 602 | matching hintKey, resolve p with 603 | true. 604 |
  6. 605 |
  7. Otherwise, resolve p with false. 606 |
  8. 607 |
608 |
609 |
610 |

611 | set() method 612 |

613 |

614 | When called, this method executes the following steps: 615 |

616 |
    617 |
  1. Let permission be the result of running 618 | retrieving 619 | the permission state of the permission associated with 620 | credential handler's origin. 621 |
  2. 622 |
  3. If permission is not "granted", then return a 623 | Promise rejected with a NotAllowedError. 624 |
  4. 625 |
  5. If the icons member of 626 | hint is present, then: 627 |
      628 |
    1. Let convertedIcons be the result of running the 629 | convert image objects algorithm passing 630 | hint.icons as the argument. 632 |
    2. 633 |
    3. If the convertedIcons is an empty 634 | Sequence, then return a Promise rejected with a 635 | TypeError. 636 |
    4. 637 |
    5. Set hint.icons to 639 | convertedIcons. 640 |
    6. 641 |
    642 |
  6. 643 |
  7. Let p be a new promise. 644 |
  8. 645 |
  9. Return p and perform the remaining steps in 646 | parallel: 647 |
  10. 648 |
  11. If the icons member of 649 | hint is present, then for each icon in 650 | hint.icons: 651 |
      652 |
    1. If the user agent wants to display the icon, 653 | then: 654 |
        655 |
      1. Let fetchedImage be the result of running 656 | the fetching image 658 | object passing icon as the argument. 659 |
      2. 660 |
      3. Set icon.[[\fetchedImage]] to 661 | fetchedImage. 662 |
      4. 663 |
      664 |
    2. 665 |
    666 |
  12. 667 |
  13. If the collection contains a CredentialHint with a 668 | matching hintKey, replace it with the 669 | CredentialHint in hint. 670 |
  14. 671 |
  15. Otherwise, insert the CredentialHint in 672 | hint as a new member of the collection and associate 673 | it with the key hintKey. 674 |
  16. 675 |
  17. Resolve p. 676 |
  18. 677 |
678 |
679 |
680 |

681 | clear() method 682 |

683 |

684 | When called, this method executes the following steps: 685 |

686 |
    687 |
  1. Let p be a new promise. 688 |
  2. 689 |
  3. Return p and perform the remaining steps in 690 | parallel: 691 |
  4. 692 |
  5. Remove all CredentialHints from the collection and 693 | resolve p. 694 |
  6. 695 |
696 |
697 |
699 |

700 | CredentialHint dictionary 701 |

702 |
 703 |       dictionary CredentialHint {
 704 |         required DOMString name;
 705 |         sequence<ImageObject> icons;
 706 |         sequence<DOMString> enabledTypes;
 707 |         object match;
 708 |       };
 709 |       
710 |
711 |
712 | name member 713 |
714 |
715 | The name member is a string that represents the label for 716 | this CredentialHint as it is usually displayed to the 717 | user. 718 |
719 |
720 | icons member 721 |
722 |
723 | The icons member is an array of image objects that can 724 | serve as iconic representations of the credential hint when 725 | presented to the user for selection. 726 |
727 |
728 | enabledTypes member 729 |
730 |
731 | The enabledTypes member is a list of one or more 732 | WebCredential types of the WebCredential types 733 | supported by this hint. 734 |
735 |
736 | match member 737 |
738 |
739 | The match member is a list of WebCredential-type-specific 740 | information that, if present in a credential request or 741 | credential storage request, must match in order for this 742 | credential hint to be considered compatible. For example, for the 743 | VerifiableProfile WebCredential type, this object may 744 | consist of an object with one field VerifiableProfile 745 | that has a value that is another object with one field id 746 | with a string value that is an identifier for an entity for which 747 | VerifiableProfiles may be constructed or stored. 748 |
749 |
750 |
751 |
752 |

753 | ImageObject dictionary 754 |

755 |
 756 |       dictionary ImageObject {
 757 |           required USVString src;
 758 |           DOMString sizes;
 759 |           DOMString type;
 760 |       };
 761 |       
762 |
763 |
764 | src member 765 |
766 |
767 | The src member is used to specify the ImageObject's 768 | source. It is a URL from which the user agent can fetch the 769 | image’s data. 770 |
771 |
772 | sizes member 773 |
774 |
775 | The sizes member is used to specify the 776 | ImageObject's sizes. It follows the spec of sizes member 777 | in HTML link element, 778 | which is a string consisting of an unordered 780 | set of unique space-separated tokens which are ASCII case-insensitive that 782 | represents the dimensions of an image. Each keyword is either an 783 | ASCII 784 | case-insensitive match for the string "any", or a value that 785 | consists of two valid non-negative integers that do not have a 786 | leading U+0030 DIGIT ZERO (0) character and that are separated by 787 | a single U+0078 LATIN SMALL LETTER X or U+0058 LATIN CAPITAL 788 | LETTER X character. The keywords represent icon sizes in raw 789 | pixels (as opposed to CSS pixels). When multiple image objects 790 | are available, a user agent MAY use the value to decide which 791 | icon is most suitable for a display context (and ignore any that 792 | are inappropriate). The parsing steps for the sizes member 793 | MUST follow the parsing 794 | steps for HTML link element sizes attribute. 795 |
796 |
797 | type member 798 |
799 |
800 | The type member is used to specify the 801 | ImageObject's MIME type. It is a hint as to the media type 802 | of the image. The purpose of this member is to allow a user agent 803 | to ignore images of media types it does not support. 804 |
805 |
806 |
807 |
808 |

809 | Convert image objects 810 |

811 |

812 | When this algorithm with inputImages parameter is 813 | invoked, the user agent must run the following steps: 814 |

815 |
    816 |
  1. Let outputImages be an empty Sequence of 817 | ImageObject. 818 |
  2. 819 |
  3. For each image in inputImages: 820 |
      821 |
    1. If image.type 822 | is not a valid MIME type or 823 | the value of type is not a supported media format, then return 824 | an empty Sequence of ImageObject. 825 |
    2. 826 |
    3. If image.sizes is not a valid value, then return an empty 829 | Sequence of ImageObject. 830 |
    4. 831 |
    5. Let url be the result of parsing 832 | image.src with the 833 | context object's 834 | relevant settings 835 | object's API base 836 | URL. 837 |
    6. 838 |
    7. If url is failure, then return an empty 839 | Sequence of ImageObject. 840 |
    8. 841 |
    9. If url's scheme is not "https", then 843 | return an empty Sequence of ImageObject. 844 |
    10. 845 |
    11. Set image.src 846 | to url. 847 |
    12. 848 |
    13. Append image to outputImages 849 |
    14. 850 |
    851 |
  4. 852 |
  5. Return outputImages. 853 |
  6. 854 |
855 |

856 | According to the step 2.3, it is also possible to use the relative 857 | url for image.src. The 858 | following examples illustrate how relative URL resolution works in 859 | different execution contexts. 860 |

861 |
 863 |         <-- In this example, code is located in https://www.example.com/wallet/index.html -->
 864 |         <script>
 865 | 
 866 |         const hintKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
 867 |         const { registration } = await navigator.serviceWorker.register("/register/sw.js");
 868 |         await registration.credentialManager.credentialHints.set({
 869 |           hintKey,
 870 |           {
 871 |             name: "My social account: pat@example.com",
 872 |             enabledTypes: ["VerifiableProfile"],
 873 |             icons: [{
 874 |               src: "icon/lowres.webp",
 875 |               sizes: "48x48",
 876 |               type: "image/webp"
 877 |             }],
 878 |             match: {
 879 |               VerifiableProfile: {
 880 |                 id: 'did:method1:1234-1234-1234-1234'
 881 |               }
 882 |             }
 883 |           });
 884 | 
 885 |         const { storedHint } =
 886 |           await registration.credentialManager.credentialHints.get(hintKey);
 887 | 
 888 |         // storedHint.icons[0].src == "https://www.example.com/wallet/icon/lowres.webp";
 889 | 
 890 |         </script>
 891 |       
892 |
 894 | 
 895 |         // In this example, code is located in https://www.example.com/register/sw.js
 896 | 
 897 |         const hintKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
 898 |         await self.registration.credentialManager.credentialHints.set({
 899 |           hintKey,
 900 |           {
 901 |             name: "My social account: pat@example.com",
 902 |             enabledTypes: ["VerifiableProfile"],
 903 |             icons: [{
 904 |               src: "../wallet/icon/lowres.webp",
 905 |               sizes: "48x48",
 906 |               type: "image/webp"
 907 |             }],
 908 |             match: {
 909 |               VerifiableProfile: {
 910 |                 id: 'did:method1:1234-1234-1234-1234'
 911 |               }
 912 |             }
 913 |           });
 914 | 
 915 |         const { storedHint } =
 916 |           await registration.credentialManager.credentialHints.get(hintKey);
 917 | 
 918 |         // storedHint.icons[0].src == "https://www.example.com/wallet/icon/lowres.webp";
 919 |       
920 |
921 |
922 |

923 | Registration Example 924 |

925 |

926 | The following example shows how to register a credential handler: 927 |

928 |
 929 |         button.addEventListener("click", async() => {
 930 |           if (!window.CredentialManager) {
 931 |             return; // not supported, so bail out.
 932 |           }
 933 | 
 934 |           const result = await CredentialManager.requestPermission();
 935 |           if (result !== "granted") {
 936 |             return;
 937 |           }
 938 | 
 939 |           const { registration } =
 940 |             await navigator.serviceWorker.register('/sw.js');
 941 | 
 942 |           // Excellent, we got it! Let's now set up the user's hints.
 943 |           await addInstruments(registration);
 944 |         }, { once: true });
 945 | 
 946 |         function addHints(registration) {
 947 |           return Promise.all([
 948 |             registration.credentialManager.hints.set(
 949 |               "dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
 950 |               {
 951 |                 name: "My social account: pat@example.com",
 952 |                 enabledTypes: ["VerifiableProfile"],
 953 |                 icons: [{
 954 |                   src: "icon/lowres.webp",
 955 |                   sizes: "48x48",
 956 |                   type: "image/webp"
 957 |                 }],
 958 |                 match: {
 959 |                   VerifiableProfile: {
 960 |                     id: 'did:method1:1234-1234-1234-1234'
 961 |                   }
 962 |                 }
 963 |               }),
 964 | 
 965 |             registration.credentialManager.hints.set(
 966 |               "c8126178-3bba-4d09-8f00-0771bcfd3b11",
 967 |               {
 968 |                 name: "My business account: pat@business.example.com",
 969 |                 enabledTypes: ["VerifiableProfile"],
 970 |                 match: {
 971 |                   VerifiableProfile: {
 972 |                     id: 'did:method1:1234-1234-1234-1235'
 973 |                   }
 974 |                 }
 975 |               }),
 976 | 
 977 |             registration.credentialManager.hints.set(
 978 |               "new-hint",
 979 |               {
 980 |                 name: "Add a new identity",
 981 |                 enabledTypes: ["VerifiableProfile"]
 982 |               }),
 983 |             ]);
 984 |           };
 985 |      
986 |
987 |
988 |
989 |
990 |

991 | Origin and Hint Display for Selection 992 |

993 | 994 |

995 | TODO: define matching algorithm here 996 |

997 |

998 | After applying the matching algorithm, the user agent displays the 999 | matching credential hints for the user to make a selection. This 1000 | specification includes a limited number of display requirements; most 1001 | user experience details are left to implementers. 1002 |

1003 |
1004 |

1005 | Ordering of Credential Hints 1006 |

1007 | 1018 |

1019 | The following are examples of credential hint ordering: 1020 |

1021 | 1035 |
1036 |
1037 |

1038 | Display of Hints 1039 |

1040 |

1041 | The user agent MUST enable the user to 1042 | select any displayed hint. 1043 |

1044 | 1049 |
1050 |
1051 |

1052 | Selection of Credential Handlers 1053 |

1054 |

1055 | Users agents may wish to enable the user to select individual 1056 | displayed CredentialHints. The credential handler would receive 1057 | information about the selected hint and could take action, potentially 1058 | eliminating an extra click (first open the credential repository 1059 | app then select the hint). 1060 |

1061 |
1062 |
1063 |
1064 |

1065 | Invocation 1066 |

1067 |

1068 | Only when a website invokes the get() 1070 | and passes a WebCredentialRequestOptions 1071 | or the store() 1073 | method and passes a WebCredential, will CredentialHints be 1074 | presented to the user for selection. 1075 |

1076 |

1077 | Once the user has selected a CredentialHint, the user agent fires a 1078 | CredentialRequestEvent (or a CredentialStoreEvent if 1079 | the Credential Management method called was store()) and uses 1080 | the subsequent WebCredential as a response. 1081 |

1082 |
1083 |

1084 | WebCredential interface 1085 |

1086 |
1087 |       [SecureContext, Exposed=(Window,Worker)]
1088 |       interface WebCredential : Credential {
1089 |           readonly attribute USVString dataType;
1090 |           readonly attribute object data;
1091 |       };
1092 |       
1093 |
1094 |
1096 |

1097 | Extension to ServiceWorkerGlobalScope 1098 |

1099 |

1100 | This specification extends the ServiceWorkerGlobalScope 1101 | interface. 1102 |

1103 |
1104 |         partial interface ServiceWorkerGlobalScope {
1105 |           attribute EventHandler oncredentialrequest;
1106 |           attribute EventHandler oncredentialstore;
1107 |         };
1108 |         
1109 |
1110 |

1111 | oncredentialrequest attribute 1112 |

1113 |

1114 | The oncredentialrequest attribute is an event handler 1115 | whose corresponding event handler event type is 1116 | CredentialRequestEvent. 1117 |

1118 |
1119 |
1120 |

1121 | oncredentialstore attribute 1122 |

1123 |

1124 | The oncredentialstore attribute is an event handler 1125 | whose corresponding event handler event type is 1126 | CredentialStoreEvent. 1127 |

1128 |
1129 |
1130 |
1132 |

1133 | The CredentialRequestEvent 1134 |

1135 |

1136 | The CredentialRequestEvent represents the data and methods available 1137 | to a Credential Handler after selection by the user. The user agent 1138 | communicates the WebCredentialRequestOptions to the Credential 1139 | Handler. 1140 |

1141 |
1142 |         [Constructor(DOMString type, CredentialRequestEventInit eventInitDict), Exposed=ServiceWorker]
1143 |         interface CredentialRequestEvent : ExtendableEvent {
1144 |           readonly attribute USVString credentialRequestOrigin;
1145 |           readonly attribute object credentialRequestOptions;
1146 |           readonly attribute DOMString hintKey;
1147 |           Promise<WindowClient?> openWindow(USVString url);
1148 |           void respondWith(Promise<WebCredential>handlerResponsePromise);
1149 |         };
1150 |         
1151 |
1152 |

1153 | credentialRequestOrigin attribute 1154 |

1155 |

1156 | This attribute is a string that indicates the origin where the [[!credential-managment-1]] 1158 | method get() was called. 1159 |

1160 |

1163 | The origin information of the relying party may be blinded when 1164 | received via a CredentialRequestEvent. It would be blinded to 1165 | allow it to still be signed without revealing where the request 1166 | came from. The user agent would be responsible for indicating 1167 | the origin of the request via its user interface. 1168 |

1169 |
1170 |
1171 |

1172 | credentialRequestOptions attribute 1173 |

1174 |

1175 | This attribute contains WebCredentialRequestOptions 1176 | dictionary containing the WebCredential type and 1177 | type-specific query that describes the credentials requested by 1178 | the web site. 1179 |

1180 |
1181 |
1182 |

1183 | hintKey attribute 1184 |

1185 |

1186 | This attribute indicates the CredentialHint selected by 1187 | the user. It corresponds to the hintKey provided to the 1189 | CredentialManager.hints interface during registration. 1190 |

1191 |
1192 |
1193 |

1194 | openWindow() method 1195 |

1196 |

1197 | This method is used by the credential handler to show a window to 1198 | the user. When called, it runs the open window algorithm. 1199 |

1200 |
1201 |
1202 |

1203 | respondWith() method 1205 |

1206 |

1207 | This method is used by the credential handler to provide a 1208 | WebCredential when the request has been fulfilled. When 1209 | called, it runs the Respond to Credential Request 1210 | Algorithm with event and 1211 | handlerResponsePromise as arguments. 1212 |

1213 |
1214 |
1215 |

1216 | CredentialRequestEventInit dictionary 1217 |

1218 |
1219 |             dictionary CredentialRequestEventInit : ExtendableEventInit {
1220 |               USVString credentialRequestOrigin;
1221 |               WebCredentialRequestOptions credentialRequestOptions;
1222 |               DOMString hintKey;
1223 |             };
1224 |           
1225 |

1226 | The credentialRequestOrigin, 1227 | credentialRequestOptions, and 1228 | hintKey members share their definitions with those 1229 | defined for CredentialRequestEvent. 1230 |

1231 |
1232 |
1233 |
1234 |

1235 | Internal Slots 1236 |

1237 |

1238 | Instances of CredentialRequestEvent are created with the 1239 | internal slots in the following table: 1240 |

1241 | 1242 | 1243 | 1246 | 1249 | 1252 | 1253 | 1254 | 1257 | 1260 | 1265 | 1266 | 1267 | 1270 | 1273 | 1278 | 1279 | 1280 | 1283 | 1286 | 1289 | 1290 |
1244 | Internal Slot 1245 | 1247 | Default Value 1248 | 1250 | Description (non-normative) 1251 |
1255 | [[\windowClient]] 1256 | 1258 | null 1259 | 1261 | The currently active WindowClient. This is set if a 1262 | credential handler is currently showing a window to the user. 1263 | Otherwise, it is null. 1264 |
1268 | [[\fetchedImage]] 1269 | 1271 | undefined 1272 | 1274 | This value is a result of fetching image object 1276 | or a fallback image provided by the user agent. 1277 |
1281 | [[\respondWithCalled]] 1282 | 1284 | false 1285 | 1287 | YAHO 1288 |
1291 |
1292 |
1293 |

1294 | Handling a CredentialRequestEvent 1295 |

1296 |

1297 | Upon receiving a credential request by way of get() and 1299 | subsequent user selection of a credential hint, the user 1300 | agent MUST run the following steps: 1301 |

1302 |
    1303 |
  1. Let registration be the 1304 | ServiceWorkerRegistration corresponding to the 1305 | CredentialHint selected by the user. 1306 |
  2. 1307 |
  3. If registration is not found, reject the 1308 | Promise that was created by get() 1310 | with a DOMException whose value is "InvalidStateError" 1311 | and terminate these steps. 1312 |
  4. 1313 |
  5. Invoke the handle functional event algorithm with a 1314 | ServiceWorkerRegistration of registration and 1315 | callbackSteps set to the following steps: 1316 |
      1317 |
    1. Set global to the global object that was provided 1318 | as an argument. 1319 |
    2. 1320 |
    3. Create a trusted event, e, that uses the 1321 | CredentialRequestEvent interface, with the event type 1322 | credentialrequest, which does not bubble, cannot be 1323 | canceled, and has no default action. 1324 |
    4. 1325 |
    5. Set the credentialRequestOrigin 1327 | attribute of e to the origin of the context where 1328 | get() 1330 | was called. 1331 |
    6. 1332 |
    7. Set the credentialRequestOptions 1334 | attributes of e to the options passed to 1335 | get(). 1337 |
    8. 1338 |
    9. Set the hintKey attribute 1340 | of e to the hintKey of the selected 1341 | CredentialHint. 1342 |
    10. 1343 |
    11. Dispatch e to global. 1344 |
    12. 1345 |
    13. Wait for all of the promises in the extend lifetime 1346 | promises of e to resolve. 1347 |
    14. 1348 |
    15. If the credential handler has not provided a 1349 | WebCredential or null, reject the Promise that was 1350 | created by get() 1352 | with a DOMException whose value "OperationError". 1353 |
    16. 1354 |
    1355 |
  6. 1356 |
1357 |
1358 |
1360 |

1361 | The CredentialStoreEvent 1362 |

1363 |

1364 | The CredentialStoreEvent represents the data and methods available to 1365 | a Credential Handler after selection by the user. The user agent 1366 | communicates the WebCredential to be stored to the 1367 | Credential Handler. 1368 |

1369 |
1370 |         [Constructor(DOMString type, CredentialStoreEventInit eventInitDict), Exposed=ServiceWorker]
1371 |         interface CredentialStoreEvent : ExtendableEvent {
1372 |           readonly attribute USVString credentialRequestOrigin;
1373 |           readonly attribute object credential;
1374 |           readonly attribute DOMString hintKey;
1375 |           Promise<WindowClient?> openWindow(USVString url);
1376 |           void respondWith(Promise<WebCredential>handlerResponsePromise);
1377 |         };
1378 |         
1379 |
1380 |

1381 | credentialRequestOrigin attribute 1382 |

1383 |

1384 | This attribute is a string that indicates the origin where the [[!credential-managment-1]] 1386 | method store() was called. 1387 |

1388 |
1389 |
1390 |

1391 | credential attribute 1392 |

1393 |

1394 | This attribute contains WebCredential dictionary containing 1395 | the specific credential information that the web site is requesting 1396 | the user to store. 1397 |

1398 |
1399 |
1400 |

1401 | hintKey attribute 1402 |

1403 |

1404 | This attribute indicates the CredentialHint selected by 1405 | the user. It corresponds to the hintKey provided to the 1407 | CredentialManager.hints interface during registration. 1408 |

1409 |
1410 |
1411 |

1412 | openWindow() method 1413 |

1414 |

1415 | This method is used by the credential handler to show a window to 1416 | the user. When called, it runs the open window algorithm. 1417 |

1418 |
1419 |
1420 |

1421 | respondWith() method 1423 |

1424 |

1425 | This method is used by the credential handler to provide a 1426 | WebCredential when the storage request has been fulfilled. 1427 | When called, it runs the Respond to Store Credential 1428 | Algorithm with event and 1429 | handlerResponsePromise as arguments. 1430 |

1431 |
1432 |
1433 |

1434 | CredentialStoreEventInit dictionary 1435 |

1436 |
1437 |             dictionary CredentialStoreEventInit : ExtendableEventInit {
1438 |               USVString credentialRequestOrigin;
1439 |               WebCredential credential;
1440 |               DOMString hintKey;
1441 |             };
1442 |           
1443 |

1444 | The credentialRequestOrigin, credential, and 1445 | hintKey members share their definitions with those 1446 | defined for CredentialStoreEvent. 1447 |

1448 |
1449 |
1450 |
1451 |

1452 | Internal Slots 1453 |

1454 |

1455 | Instances of CredentialStoreEvent are created with the 1456 | internal slots in the following table: 1457 |

1458 | 1459 | 1460 | 1463 | 1466 | 1469 | 1470 | 1471 | 1474 | 1477 | 1482 | 1483 | 1484 | 1487 | 1490 | 1495 | 1496 | 1497 | 1500 | 1503 | 1506 | 1507 |
1461 | Internal Slot 1462 | 1464 | Default Value 1465 | 1467 | Description (non-normative) 1468 |
1472 | [[\windowClient]] 1473 | 1475 | null 1476 | 1478 | The currently active WindowClient. This is set if a 1479 | credential handler is currently showing a window to the user. 1480 | Otherwise, it is null. 1481 |
1485 | [[\fetchedImage]] 1486 | 1488 | undefined 1489 | 1491 | This value is a result of fetching image object 1493 | or a fallback image provided by the user agent. 1494 |
1498 | [[\respondWithCalled]] 1499 | 1501 | false 1502 | 1504 | YAHO 1505 |
1508 |
1509 |
1510 |

1511 | Handling a CredentialStoreEvent 1512 |

1513 |

1514 | Upon receiving a credential storage request by way of store() 1516 | and subsequent user selection of a credential hint, the user 1517 | agent MUST run the following steps: 1518 |

1519 |
    1520 |
  1. Let registration be the 1521 | ServiceWorkerRegistration corresponding to the 1522 | CredentialHint selected by the user. 1523 |
  2. 1524 |
  3. If registration is not found, reject the 1525 | Promise that was created by store() 1527 | with a DOMException whose value is "InvalidStateError" 1528 | and terminate these steps. 1529 |
  4. 1530 |
  5. Invoke the handle functional event algorithm with a 1531 | ServiceWorkerRegistration of registration and 1532 | callbackSteps set to the following steps: 1533 |
      1534 |
    1. Set global to the global object that was provided 1535 | as an argument. 1536 |
    2. 1537 |
    3. Create a trusted event, e, that uses the 1538 | CredentialStoreEvent interface, with the event type 1539 | credentialstore, which does not bubble, cannot be 1540 | canceled, and has no default action. 1541 |
    4. 1542 |
    5. Set the credentialRequestOrigin 1544 | attribute of e to the origin of the context where 1545 | store() 1547 | was called. 1548 |
    6. 1549 |
    7. Set the credential attributes of 1551 | e to the options passed to 1552 | store(). 1554 |
    8. 1555 |
    9. Set the hintKey attribute 1557 | of e to the hintKey of the selected 1558 | CredentialHint. 1559 |
    10. 1560 |
    11. Dispatch e to global. 1561 |
    12. 1562 |
    13. Wait for all of the promises in the extend lifetime 1563 | promises of e to resolve. 1564 |
    14. 1565 |
    15. If the credential handler has not provided a 1566 | WebCredential or null, reject the Promise that was 1567 | created by store() 1569 | with a DOMException whose value "OperationError". 1570 |
    16. 1571 |
    1572 |
  6. 1573 |
1574 |
1575 |
1576 |
1577 |

1578 | Windows 1579 |

1580 |

1581 | An invoked credential handler may or may not need to display information 1582 | about itself or request user input. Some examples of potential 1583 | credential handler display include: 1584 |

1585 | 1599 |

1600 | A credential handler that requires visual display and user 1601 | interaction, may call openWindow() to display a page to the user. 1602 |

1603 |

1604 | Since user agents know that this method is connected to the 1605 | CredentialRequestEvent or a CredentialStoreEvent, they 1606 | SHOULD render the window in a way that is consistent with the flow and 1607 | not confusing to the user. The resulting window client is bound to the 1608 | tab/window that initiated the request. A single 1609 | credential handler SHOULD NOT be allowed to open more than one 1610 | client window using this method. 1611 |

1612 |
1613 |

1614 | Open Window Algorithm 1615 |

1616 |

1617 | This algorithm resembles the Open Window Algorithm in 1619 | the Service Workers specification and mirrors the one provided in 1620 | the Payment Handler API specification. 1621 |

1622 |

1623 | Should we refer to the Service Workers specification instead of 1624 | copying their steps? 1625 |

1626 |
    1627 |
  1. Let event be this CredentialRequestEvent or 1628 | CredentialStoreEvent. 1629 |
  2. 1630 |
  3. Let url be the result of parsing the url argument. 1632 |
  4. 1633 |
  5. If the url parsing throws an exception, return a Promise 1634 | rejected with that exception. 1635 |
  6. 1636 |
  7. If url is about:blank, return a 1637 | Promise rejected with a TypeError. 1638 |
  8. 1639 |
  9. If url's origin is not the same as the service 1640 | worker's origin associated with the credential handler, return a 1641 | Promise resolved with null. 1642 |
  10. 1643 |
  11. If this algorithm is not triggered by user 1645 | activation, return a Promise rejected with a 1646 | InvalidAccessError. 1647 |
  12. 1648 |
  13. Let promise be a new Promise. 1649 |
  14. 1650 |
  15. Return promise and perform the remaining steps in 1651 | parallel: 1652 |
  16. 1653 |
  17. If event.[[\windowClient]] is not null, then: 1654 |
      1655 |
    1. If event.[[\windowClient]].visibilityState 1657 | is not "unloaded", reject promise with a 1658 | DOMException whose name is "InvalidStateError" and 1659 | abort these steps. 1660 |
    2. 1661 |
    1662 |
  18. 1663 |
  19. Let newContext be a new top-level browsing context. 1665 |
  20. 1666 |
  21. 1667 | Navigate newContext to 1668 | url, with exceptions enabled and replacement enabled. 1669 |
  22. 1670 |
  23. If the navigation throws an exception, reject promise 1671 | with that exception and abort these steps. 1672 |
  24. 1673 |
  25. If the origin of newContext is not the same as the 1674 | service worker client origin associated with the credential 1675 | handler, then: 1676 |
      1677 |
    1. Resolve promise with null. 1678 |
    2. 1679 |
    3. Abort these steps. 1680 |
    4. 1681 |
    1682 |
  26. 1683 |
  27. Let client be the result of running the 1684 | create 1685 | window client algorithm with newContext as the 1686 | argument. 1687 |
  28. 1688 |
  29. Set event.[[\windowClient]] to 1689 | client. 1690 |
  30. 1691 |
  31. Resolve promise with client. 1692 |
  32. 1693 |
1694 |
1695 |
1696 |

1697 | Example of handling the CredentialRequestEvent or the 1698 | CredentialStoreEvent 1699 |

1700 |

1701 | This example shows how to write a service worker that listens to the 1702 | CredentialRequestEvent and the CredentialStoreEvent. 1703 | When a CredentialRequestEvent or CredentialStoreEvent 1704 | is received, the service worker opens a window to interact with the 1705 | user. 1706 |

1707 |
1709 |       self.addEventListener('credentialrequest', function(e) {
1710 |         e.respondWith(new Promise(function(resolve, reject) {
1711 |           self.addEventListener('message', listener = function(e) {
1712 |             self.removeEventListener('message', listener);
1713 |             if (e.data.hasOwnProperty('name')) {
1714 |               reject(e.data);
1715 |             } else {
1716 |               resolve(e.data);
1717 |             }
1718 |           });
1719 | 
1720 |           e.openWindow("https://www.example.com/wallet/get")
1721 |           .then(function(windowClient) {
1722 |             windowClient.postMessage(e.data);
1723 |           })
1724 |           .catch(function(err) {
1725 |             reject(err);
1726 |           });
1727 |         }));
1728 |       });
1729 | 
1730 |       self.addEventListener('credentialstore', function(e) {
1731 |         e.respondWith(new Promise(function(resolve, reject) {
1732 |           self.addEventListener('message', listener = function(e) {
1733 |             self.removeEventListener('message', listener);
1734 |             if (e.data.hasOwnProperty('name')) {
1735 |               reject(e.data);
1736 |             } else {
1737 |               resolve(e.data);
1738 |             }
1739 |           });
1740 | 
1741 |           e.openWindow("https://www.example.com/wallet/store")
1742 |           .then(function(windowClient) {
1743 |             windowClient.postMessage(e.data);
1744 |           })
1745 |           .catch(function(err) {
1746 |             reject(err);
1747 |           });
1748 |         }));
1749 |       });
1750 |       
1751 |

1752 | Using the simple scheme described above, a trivial HTML page that is 1753 | loaded into the credential handler window might include the 1754 | following script: 1755 |

1756 |
1757 | <script>
1758 | window.addEventListener("message", function(e) {
1759 |   var credentialRequestOptions = event.data.credentialRequestOptions;
1760 | 
1761 |   // TODO: process the query found in the request options and present
1762 |   // choices to the user
1763 |   // await ...
1764 | 
1765 |   e.source.postMessage({
1766 |     type: 'response',
1767 |     credential: {
1768 |       dataType: 'VerifiableProfile',
1769 |       data: {
1770 |         '@context': 'https://w3id.org/credentials/v1',
1771 |         // ...
1772 |         signature: { ... }
1773 |       }
1774 |     }
1775 |   });
1776 |   window.close();
1777 | });
1778 | </script>
1779 |       
1780 |
1781 |
1782 |
1783 |

1784 | Response 1785 |

1786 |
1788 |

1789 | CredentialHandlerResponse dictionary 1790 |

The CredentialHandlerResponse is conveyed using the following 1791 | dictionary: 1792 |
1793 |           dictionary CredentialHandlerResponse {
1794 |           DOMString dataType;
1795 |           object data;
1796 |           };
1797 |         
1798 |
1799 |

1800 | dataType attribute 1801 |

1802 |

1803 | The WebCredential type for the credential that the user 1804 | selected to fulfill the request. 1805 |

1806 |
1807 |
1808 |

1809 | data attribute 1810 |

1811 |

1812 | A JSON-serializable object that provides a 1813 | WebCredential type specific message used by the relying 1814 | party to authenticate the user. 1815 |

1816 |

1817 | The user agent receives a successful response from the credential 1818 | handler through resolution of the Promise provided to the 1819 | respondWith() 1820 | function of the corresponding CredentialRequestEvent 1821 | interface. 1822 | The application is expected to resolve the Promise with a 1823 | CredentialHandlerResponse instance containing the response. 1824 | In case of user cancellation or error, the application may signal 1825 | failure by rejecting the Promise. 1826 |

1827 |

1828 | If the Promise is rejected, the user agent MUST run the 1829 | credential repository failure algorithm. The exact 1830 | details of this algorithm are left to implementers. Acceptable 1831 | behaviors include, but are not limited to: 1832 |

1833 |
    1834 |
  • Letting the user try again, with the same credential handler or 1835 | with a different one. 1836 |
  • 1837 |
  • Rejecting the Promise that was created by get() 1839 | or store(). 1841 |
  • 1842 |
1843 |
1844 |
1845 |
1846 |

1847 | Respond to Credential Request Algorithm 1848 |

1849 |

1850 | When this algorithm is invoked with event and 1851 | handlerResponsePromise parameters, the user agent MUST run 1852 | the following steps: 1853 |

1854 |
    1855 |
  1. If event's dispatch flag is unset, then 1856 | throw an "InvalidStateError" DOMException and 1857 | abort these steps. 1858 |
  2. 1859 |
  3. If event.[[\respondWithCalled]] is true, throw 1860 | an "InvalidStateError" DOMException and abort these 1861 | steps. 1862 |
  4. 1863 |
  5. Set event.[[\respondWithCalled]] to true. 1864 |
  6. 1865 |
  7. Set the event's stop propagation flag and 1866 | event's stop immediate propagation flag. 1867 |
  8. 1868 |
  9. Add handlerResponsePromise to the event's 1869 | extend lifetime promises 1870 |
  10. 1871 |
  11. Increment the event's pending promises count by 1872 | one. 1873 |
  12. 1874 |
  13. Upon rejection of handlerResponsePromise: 1875 |
      1876 |
    1. Run the credential repository failure algorithm and 1877 | terminate these steps. 1878 |
    2. 1879 |
    1880 |
  14. 1881 |
  15. Upon fulfillment of handlerResponsePromise: 1882 |
      1883 |
    1. Let handlerResponse be the result of 1884 | converting value to a CredentialHandlerResponse 1885 | dictionary. If this throws an exception, run the 1886 | credential repository failure algorithm and terminate 1887 | these steps. 1888 |
    2. 1889 |
    3. If handlerResponse.dataType is not 1891 | present or not set to one of the keys from 1892 | event.credentialRequestOptions 1894 | (TODO: or the dataType for WebCredential for storage), 1895 | run the credential repository failure algorithm and terminate 1896 | these steps. 1897 |
    4. 1898 |
    5. If handlerResponse.data is not present or 1900 | not JSON-serializable, run the credential repository 1901 | failure algorithm and terminate these steps. 1902 |
    6. 1903 |
    7. Let serializeDataType be the result of 1904 | StructuredSerialize 1905 | with handlerResponse.dataType. Rethrow any 1907 | exceptions. 1908 |
    8. 1909 |
    9. Let serializeData be the result of 1910 | StructuredSerialize 1911 | with handlerResponse.data. Rethrow any 1913 | exceptions. 1914 |
    10. 1915 |
    11. TODO: integrate with credential management algorithms... or 1916 | an algorithm defining the creation of a WebCredential 1917 |
        1918 |
      1. Let dataType be the result of 1919 | StructuredDeserialize 1920 | with serializeDataType. Rethrow any 1921 | exceptions. 1922 |
      2. 1923 |
      3. Let data be the result of StructuredDeserialize with 1925 | serializeData. Rethrow any exceptions. 1926 |
      4. 1927 |
      5. If any exception occurs in any of the above steps, then 1928 | run the credential repository failure algorithm and 1929 | terminate these steps. 1930 |
      6. 1931 |
      7. Assign dataType to associated 1932 | WebCredential's credential.dataType. 1934 |
      8. 1935 |
      9. Assign data to associated WebCredential's 1936 | credential.data. 1938 |
      10. 1939 |
      1940 |
    12. 1941 |
    1942 |
  16. 1943 |
  17. Upon fulfillment or rejection of 1944 | handlerResponsePromise, queue a microtask to perform the 1946 | following steps: 1947 |
      1948 |
    1. Decrement the event's pending promises 1949 | count by one. 1950 |
    2. 1951 |
    3. Let registration be the context object's relevant global object's 1954 | associated service worker's containing service worker 1955 | registration. 1956 |
    4. 1957 |
    5. If registration’s uninstalling flag is set, 1958 | invoke Try Clear Registration with 1959 | registration. 1960 |
    6. 1961 |
    7. If registration is not null, invoke Try 1962 | Activate with registration. 1963 |
    8. 1964 |
    1965 |
  18. 1966 |
1967 |

1968 | The following example shows how to respond to a credential request: 1969 |

1970 |
1971 |       credentialRequestEvent.respondWith(new Promise(function(accept,reject) {
1972 |         /* ... processing may occur here ... */
1973 |         accept({
1974 |           dataType: "VerifiableProfile",
1975 |           data: {
1976 |             "@context": "https://w3id.org/credentials/v1",
1977 |             // ...
1978 |            }
1979 |         });
1980 |       }));
1981 |           
1982 |
1983 |
1984 |
1985 |

1986 | Security and Privacy Considerations 1987 |

1988 |
1989 |

1990 | Information about the User Environment 1991 |

1992 | 2002 |
2003 |
2004 |

2005 | User Consent Before Sending Credentials 2006 |

2007 | 2015 |
2016 |
2017 |

2018 | Secure Communications 2019 |

2020 | 2029 |
2030 |
2031 |

2032 | Credential Repository Authenticity 2033 |

2034 | 2043 |
2044 |
2045 |

2046 | Data Validation 2047 |

2048 | 2054 |
2055 |
2056 |

2057 | Private Browsing Mode 2058 |

2059 | 2068 |
2069 |
2070 |
2071 |

2072 | Dependencies 2073 |

2074 |

2075 | This specification relies on several other underlying specifications. 2076 |

2077 |
2078 |
2079 | Credential Management API 2080 |
2081 |
2082 | get(), 2084 | and 2085 | store() 2087 | are defined by the Credential Management Level 1 specification 2088 | [[!credential-management-1]]. 2089 |
2090 |
2091 | ECMA-262 6th Edition, The ECMAScript 2015 Language Specification 2092 |
2093 |
2094 | The terms Promise, internal 2097 | slot, 2099 | TypeError, and JSON.stringify are 2101 | defined by [[!ECMA-262-2015]]. 2102 |

2103 | The term JSON-serialize applied to 2105 | a given object means to run the algorithm specified by the original 2106 | value of the JSON.stringify function on the supplied object, 2107 | passing the supplied object as the sole argument, and return the 2108 | resulting string. This can throw an exception. 2109 |

2110 |
2111 |
2112 | HTML5 2113 |
2114 |
2115 | The terms global object, 2116 | top-level browsing 2117 | context, structured 2118 | clone, event 2119 | handler, event 2120 | handler event type, trusted event, and 2122 | user interaction 2123 | task source are defined by [[!HTML5]]. 2124 |
2125 |
2126 | RFC6454 2127 |
2128 |
2129 | The term origin is defined in [[!RFC6454]]. 2130 |
2131 |
2132 | Writing Promise-Using Specifications 2133 |
2134 |
2135 | The terms upon fulfillment and upon 2137 | rejection are 2138 | defined by [[!PROMISES-GUIDE]]. 2139 |
2140 |
2141 | DOM 2142 |
2143 |
2144 | The term fires (an event), 2145 | dispatch flag, 2146 | stop propagation 2147 | flag, and stop immediate propagation 2149 | flag are defined in [[!DOM4]]. 2150 |
2151 |
2152 | Web IDL 2153 |
2154 |
2155 |

2156 | When this specification says to throw an error, the user agent must 2158 | throw an error as described in [[!WEBIDL]]. When this occurs in a 2159 | sub-algorithm, this results in termination of execution of the 2160 | sub-algorithm and all ancestor algorithms until one is reached that 2161 | explicitly describes procedures for catching exceptions. 2162 |

2163 |

2164 | The algorithm for converting an ECMAScript value to a dictionary 2167 | is defined by [[!WEBIDL]]. 2168 |

2169 |

2170 | DOMException and 2171 | the following DOMException types from [[!WEBIDL-LS]] are 2172 | used: 2173 |

2174 |
    2175 |
  • "InvalidAccessError" 2177 |
  • 2178 |
  • "InvalidStateError" 2180 |
  • 2181 |
  • "NotAllowedError" 2183 |
  • 2184 |
  • "NotFoundError" 2186 |
  • 2187 |
  • "OperationError" 2189 |
  • 2190 |
  • "SecurityError" 2192 |
  • 2193 |
2194 |
2195 |
2196 | Secure Contexts 2197 |
2198 |
2199 | The term secure 2200 | context is defined by the Secure Contexts specification 2201 | [[!SECURE-CONTEXTS]]. 2202 |
2203 |
2204 | Service Workers 2205 |
2206 |
2207 | The terms service worker, 2209 | service 2210 | worker client, ServiceWorkerRegistration, 2212 | ServiceWorkerGlobalScope, 2214 | handle 2216 | functional event, extend lifetime 2218 | promises,pending promises 2220 | count, containing 2222 | service worker registration, uninstalling flag, 2224 | Try Clear 2226 | Registration, Try Activate, and 2228 | scope URL are 2229 | defined in [[!SERVICE-WORKERS]]. 2230 |
2231 |
2232 |
2233 |
2234 | 2235 |
2236 |

Acknowledgements

2237 | 2238 |

The authors would like to acknowledge the editors and authors of the 2239 | Payment Request and Payment Handler specifications as this specification 2240 | has been largely influenced by their design and language.

2241 | 2242 |

TODO

2243 |
2244 | 2245 | 2246 | --------------------------------------------------------------------------------