@@ -155,7 +155,7 @@ could be implemented.
155155 // Prompt the user to select an account from the IDP to use for
156156 // federated login within the RP. If resolved successfully, the Promise
157157 // returns an IdentityCredential object from which the |token| can be
158- // extracted. This is an opaque string passed from the IDP to the RP.
158+ // extracted. This is passed from the IDP to the RP and can be any type of value .
159159 let token = await navigator.credentials.get({
160160 identity: {
161161 providers: [{
@@ -164,6 +164,14 @@ could be implemented.
164164 }]
165165 }
166166 });
167+
168+ // Handle the token - it could be a string or JSON object
169+ let token = credential.token;
170+ if (typeof token === 'object' && token !== null) {
171+ // Handle structured token (e.g., OAuth response)
172+ } else if (typeof token === 'string' ) {
173+ // Handle string token (e.g., JWT)
174+ }
167175 } catch(e) {
168176 // The FedCM call was not successful.
169177 }
@@ -453,7 +461,7 @@ This specification introduces a new type of {{Credential}}, called an {{Identity
453461 [Exposed=Window, SecureContext]
454462 interface IdentityCredential : Credential {
455463 static Promise<undefined> disconnect(IdentityCredentialDisconnectOptions options);
456- readonly attribute USVString? token;
464+ readonly attribute any token;
457465 readonly attribute boolean isAutoSelected;
458466 readonly attribute USVString configURL;
459467 };
@@ -465,6 +473,8 @@ This specification introduces a new type of {{Credential}}, called an {{Identity
465473 : <b> {{IdentityCredential/token}} </b>
466474 :: The {{IdentityCredential/token}} 's attribute getter returns the value it is set to.
467475 It represents the minted {{IdentityAssertionResponse/token}} provided by the [=IDP=] .
476+ The type returned depends on what the [=IDP=] provides in its assertion endpoint response.
477+ [=RP=] MUST check the type of the token before processing it.
468478 : <b> {{IdentityCredential/isAutoSelected}} </b>
469479 :: {{IdentityCredential/isAutoSelected}} 's attribute getter returns the value it is
470480 set to. It represents whether the user's identity credential was automatically selected when
@@ -1514,11 +1524,11 @@ To <dfn>fetch an identity assertion</dfn> given a {{USVString}}
15141524 1. Set |credential| to the result of [=create an IdentityCredentialError=] with {} and
15151525 |globalObject|.
15161526 1. The user agent MAY set |credential|'s {{IdentityCredentialError/error}} based on
1517- |response|'s [=response/status=] . For example, if the [=response/status=] is 500, it
1518- could set it to "server_error", and if the [=response/status=] is 503, it could set
1527+ |response|'s [=response/status=] . For example, if the [=response/status=] is ` 500` , it
1528+ could set it to "server_error", and if the [=response/status=] is ` 503` , it could set
15191529 it to "temporarily_unavailable".
1520- 1. Otherwise, if {{IdentityAssertionResponse/token}} was specified, let |tokenString|
1521- be |token|'s {{IdentityAssertionResponse/token}} .
1530+ 1. Otherwise, if {{IdentityAssertionResponse/token}} was specified:
1531+ 1. Let |tokenValue| be |token|'s {{IdentityAssertionResponse/token}} .
15221532 1. Otherwise, if {{IdentityAssertionResponse/continue_on}} was specified, run these steps
15231533 [=in parallel=] :
15241534 1. Let |continueOnUrl| be the result of running [=parse url=] with |token|'s
@@ -1528,19 +1538,19 @@ To <dfn>fetch an identity assertion</dfn> given a {{USVString}}
15281538 to failure and return.
15291539 1. Let |tokenPair| be the result of [=show a continuation dialog=] with |continueOnUrl|.
15301540 1. If |tokenPair| is failure, set |credential| to failure and return.
1531- 1. Let |tokenString | be the first entry of |tokenPair|.
1541+ 1. Let |tokenValue | be the first entry of |tokenPair|.
15321542 1. If the second entry of |tokenPair| is not null, set |accountId| to that second entry.
15331543 1. Otherwise, set |credential| to a the result of [=create an IdentityCredentialError=] with
15341544 {} and |globalObject|,
1535- 1. Wait for |tokenString | or |credential| to be set.
1545+ 1. Wait for |tokenValue | or |credential| to be set.
15361546 1. If |credential| is set:
15371547 1. Assert that |credential| is set to failure.
15381548 1. Return |credential|.
15391549 1. [=Create a connection between the RP and the IdP account=] with |provider|, |accountId|, and
15401550 |globalObject|.
15411551 1. Let |credential| be a new {{IdentityCredential}} given |globalObject|'s
15421552 <a for="global object">realm</a> .
1543- 1. Set |credential|'s {{IdentityCredential/token}} to |tokenString |.
1553+ 1. Set |credential|'s {{IdentityCredential/token}} to |tokenValue |.
15441554 1. Set |credential|'s {{IdentityCredential/isAutoSelected}} to
15451555 |isAutoSelected|.
15461556 1. Set |credential|'s {{IdentityCredential/configURL}} to |provider|' s
@@ -1580,7 +1590,7 @@ An extension may add the following steps after the [=fetch identity assertion/cr
15801590
15811591<pre class="idl">
15821592dictionary IdentityAssertionResponse {
1583- USVString token;
1593+ any token;
15841594 USVString continue_on;
15851595 IdentityCredentialErrorInit error;
15861596};
@@ -1812,7 +1822,7 @@ success or failure.
18121822
18131823<div algorithm>
18141824To <dfn>show a continuation dialog</dfn> given a |continueOnUrl|, run the
1815- following steps. This returns a failure or a tuple (string , string?) (a token
1825+ following steps. This returns a failure or a tuple (any , string?) (a token
18161826and an optional account ID).
18171827 1. Assert: these steps are running [=in parallel=] .
18181828 1. [=Create a fresh top-level traversable=] with |continueOnUrl|.
@@ -1828,11 +1838,11 @@ and an optional account ID).
18281838 * {{IdentityProvider}} .{{IdentityProvider/resolve()}} is called in
18291839 the context of this new traversable.
18301840 1. Close the traversable.
1831- 1. Let |token | be the token that was passed to that resolve call.
1841+ 1. Let |tokenValue | be the token that was passed to that resolve call.
18321842 1. If {{IdentityResolveOptions/accountId}} was specified in the
18331843 resolve call, let |accountId| be that account ID.
18341844 1. Otherwise, let |accountId| be null.
1835- 1. Return (|token |, |accountId|).
1845+ 1. Return (|tokenValue |, |accountId|).
18361846
18371847</div>
18381848
@@ -1870,7 +1880,7 @@ This specification introduces the {{IdentityUserInfo}} dictionary as well as the
18701880
18711881 [Exposed=Window, SecureContext] interface IdentityProvider {
18721882 static undefined close();
1873- static Promise<undefined> resolve(DOMString token, optional IdentityResolveOptions options = {});
1883+ static Promise<undefined> resolve(any token, optional IdentityResolveOptions options = {});
18741884 static Promise<sequence<IdentityUserInfo>> getUserInfo(IdentityProviderConfig config);
18751885 };
18761886</pre>
@@ -2425,7 +2435,10 @@ Every {{IdentityAssertionResponse}} is expected to have members with the followi
24252435
24262436<dl dfn-type="dict-member" dfn-for="IdentityAssertionResponse">
24272437 : <dfn>token</dfn>
2428- :: The resulting token.
2438+ :: The resulting token. The value is of type <a href="https://webidl.spec.whatwg.org/#idl-any">`any`</a> , allowing
2439+ [=IDPs=] to return tokens in various formats (string, object, etc.).
2440+ See the examples at the end of [[#idp-api-id-assertion-endpoint]] for both string
2441+ and object token formats.
24292442 : <dfn>continue_on</dfn>
24302443 :: A URL that the user agent will open in a popup to finish the authentication process.
24312444 : <dfn>error</dfn>
@@ -2450,7 +2463,7 @@ Portability is left entirely up to [=IDPs=], who can choose
24502463between a variety of different mechanisms to accomplish it
24512464(e.g. [OIDC's Account Porting] (https://openid.net/specs/openid-connect-account-porting-1_0.html)).
24522465
2453- For example :
2466+ Example (string token) :
24542467
24552468<div class=example>
24562469```json
@@ -2460,6 +2473,16 @@ For example:
24602473```
24612474</div>
24622475
2476+ Example (JSON object token):
2477+
2478+ <div class=example>
2479+ ```json
2480+ {
2481+ { "token" : { "access_token": "eyJC...J9.eyJzdWTE2...MjM5MDIyfQ.SflV_adQssw....5c", "token_type": "Bearer", "expires_in": 3600, "scope": "openid profile email", "refresh_token": "eyJC...refresh...token" } }
2482+ }
2483+ ```
2484+ </div>
2485+
24632486<!-- ============================================================ -->
24642487## Disconnect endpoint ## {#idp-api-disconnect-endpoint}
24652488<!-- ============================================================ -->
@@ -2924,6 +2947,27 @@ distinguishing browser-initiated FedCM flows from arbitrary requests.
29242947[=IDP=] and [=RP=] endpoints are implemented correctly and do not contain vulnerabilities that could
29252948allow an attacker to bypass the FedCM flow or extract sensitive data.
29262949
2950+ <!-- ============================================================ -->
2951+ ### Token Format and Validation ### {#token-format-validation}
2952+ <!-- ============================================================ -->
2953+
2954+ **Consideration**
2955+
2956+ The FedCM API supports flexible token formats, allowing [=IDPs=] to return tokens in various forms.
2957+ [=RPs=] must be prepared to handle different token structures as agreed upon with their [=IDP=]
2958+ partners. The token content remains opaque to the user agent.
2959+
2960+ **Recommendations**
2961+
2962+ 1. [=RPs=] should implement robust token parsing logic that can handle the specific format agreed
2963+ upon with their [=IDP=] partners.
2964+ 1. [=RPs=] should validate tokens according to the security requirements and format specifications
2965+ established with their [=IDP=] .
2966+ 1. [=IDPs=] should clearly document their token format and structure to help [=RPs=] implement
2967+ proper validation.
2968+ 1. [=IDPs=] should ensure their token format is consistent and follows their documented
2969+ specification.
2970+
29272971<!-- ============================================================ -->
29282972## Threats and Attacks ## {#security-threats-aattacks}
29292973<!-- ============================================================ -->
@@ -3473,6 +3517,19 @@ These schemes have not been adopted by this specification.
34733517 </pre>
34743518</div>
34753519
3520+ <!-- ============================================================ -->
3521+ ### Token Content Privacy ### {#token-content-privacy}
3522+ <!-- ============================================================ -->
3523+
3524+ The FedCM API treats token content as opaque data, regardless of type.
3525+ This design ensures:
3526+
3527+ 1. The [=user agent=] does not semantically interpret or validate the meaning of token contents, but
3528+ may inspect their type and structure for proper handling, while maintaining the privacy of the
3529+ authentication data.
3530+ 1. The token format flexibility does not introduce new privacy risks.
3531+ 1. [=IDPs=] have flexibility in token design without compromising user privacy.
3532+
34763533<!-- ====================================================================== -->
34773534# Extensibility # {#extensibility}
34783535<!-- ====================================================================== -->
0 commit comments