Aggiornamenti di FedCM: prove dell'origine per il bundle dell'API Continuation e concessione automatica dell'API Storage Access

A partire da Chrome 126, gli sviluppatori possono iniziare a eseguire una prova dell'origine per un insieme di funzionalità dell'API FedCM (Federated Credential Management) per computer che consentono alcuni casi d'uso di autorizzazione. Il bundle è costituito dall'API Continuation e dall'API Parameters, che consentono un'esperienza simile al flusso di autorizzazione OAuth che coinvolge una finestra di dialogo di autorizzazione fornita da un provider di identità (IdP). Il bundle include anche altre modifiche, come l'API Fields, più configURL e le etichette account personalizzate. A partire da Chrome 126, stiamo anche introducendo una prova dell'origine per l'API Storage Access (SAA) che concede automaticamente le richieste SAA se l'utente ha eseguito correttamente l'accesso utilizzando FedCM in passato.

Prova dell'origine: pacchetto dell'API FedCM Continuation

Il bundle dell'API FedCM Continuation è costituito da più estensioni FedCM:

API Continuation

Un utente accede all'RP e poi esegue l'autorizzazione tramite la modalità dei pulsanti.

Puoi consultare una demo dell'API su Glitch.

L'API Continuation consente all'endpoint di affermazione dell'ID dell'IDP di restituire facoltativamente un URL che FedCM mostrerà per consentire all'utente di continuare un flusso di accesso a più passaggi. In questo modo, l'IdP può chiedere all'utente di concedere alla terza parte attendibile (RP) autorizzazioni oltre a quelle possibili nell'interfaccia utente di FedCM esistente, ad esempio l'accesso alle risorse lato server dell'utente.

In genere, l'endpoint di affermazione dell'identità restituisce un token necessario per l'autenticazione.

{
  "token": "***********"
}

Tuttavia, con l'API Continuation, l'endpoint di affermazione dell'ID può restituire una proprietà continue_on che include un percorso assoluto o relativo all'endpoint di affermazione dell'ID.

{
  // In the id_assertion_endpoint, instead of returning a typical
  // "token" response, the IdP decides that it needs the user to
  // continue on a pop-up window:
  "continue_on": "/oauth/authorize?scope=..."
}

Non appena il browser riceve la risposta continue_on, viene aperta una nuova finestra popup che indirizza l'utente al percorso specificato.

Dopo che l'utente interagisce con la pagina, ad esempio concedendo un'ulteriore autorizzazione per condividere informazioni aggiuntive con l'RP, la pagina dell'IdP può chiamare IdentityProvider.resolve() per risolvere la chiamata navigator.credentials.get() originale e restituire un token come argomento.

document.getElementById('allow_btn').addEventListener('click', async () => {
  let accessToken = await fetch('/generate_access_token.cgi');
  // Closes the window and resolves the promise (that is still hanging
  // in the relying party's renderer) with the value that is passed.
  IdentityProvider.resolve(accessToken);
});

Il browser chiuderà automaticamente il popup e restituirà il token all'autore della chiamata dell'API.

Se l'utente rifiuta la richiesta, puoi chiudere la finestra chiamando IdentityProvider.close().

IdentityProvider.close();

Se per qualche motivo l'utente ha cambiato il proprio account nel popup (ad esempio, se l'IDP offre una funzione "Cambia utente" o in caso di delega), la chiamata resolve accetta un secondo argomento facoltativo che consente qualcosa di simile a:

IdentityProvider.resolve(token, {accountId: '1234');

API Parameters

L'API Parameters consente all'RP di fornire parametri aggiuntivi all'endpoint Dichiarazione ID. Con l'API Parameters, gli RP possono passare parametri aggiuntivi all'IDP per richiedere autorizzazioni per le risorse oltre all'accesso di base. L'utente autorizzerà queste autorizzazioni tramite un flusso UX controllato dall'IDP che viene avviato tramite l'API Continuation.

Per utilizzare l'API, aggiungi i parametri alla proprietà params come oggetto nella chiamata navigator.credentials.get().

let {token} = await navigator.credentials.get({
  identity: {
    providers: [{
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      // Key/value pairs that need to be passed from the
      // RP to the IdP but that don't really play any role with
      // the browser.
      params: {
        IDP_SPECIFIC_PARAM: '1',
        foo: 'BAR',
        ETC: 'MOAR',
        scope: 'calendar.readonly photos.write',
      }
    },
  }
});

I nomi delle proprietà nell'oggetto params sono preceduti da param_. Nell'esempio precedente, la proprietà params contiene IDP_SPECIFIC_PARAM come '1', foo come 'BAR', ETC come 'MOAR' e scope come 'calendar.readonly photos.write'. Nel corpo HTTP della richiesta, questo valore verrà tradotto come param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write:

POST /fedcm_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false&param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write

Ottenere le autorizzazioni in modo dinamico

In generale, per gli utenti è più utile richiedere le autorizzazioni quando sono necessarie, anziché quando lo sviluppatore ritiene che siano più facili da implementare. Ad esempio, è preferibile chiedere l'autorizzazione per accedere a una fotocamera quando l'utente sta per scattare una foto rispetto a chiederla non appena l'utente arriva sul sito web. La stessa pratica vale per le risorse del server. Richiedi le autorizzazioni solo quando sono necessarie per l'utente. Questa operazione è chiamata "autorizzazione dinamica".

Per richiedere l'autorizzazione in modo dinamico con FedCM, l'SP può:

  1. Chiama navigator.credentials.get() con i parametri obbligatori che l'IdP può comprendere, ad esempio scope.
  2. L'endpoint di affermazione dell'ID conferma che l'utente ha già eseguito l'accesso e risponde con un URL continue_on.
  3. Il browser apre una finestra popup con la pagina delle autorizzazioni dell'IDP che richiede un'autorizzazione aggiuntiva corrispondente agli ambiti richiesti.
  4. Una volta autorizzata tramite IdentityProvider.resolve() dall'IDP, la finestra viene chiusa e la chiamata navigator.credentials.get() originale dell'RP riceve un token pertinente o un codice di autorizzazione in modo che l'RP possa scambiarlo con un token di accesso appropriato.

API Fields

L'API Fields consente all'RP di dichiarare gli attributi dell'account da richiedere all'IDP in modo che il browser possa visualizzare un'interfaccia utente di informativa adeguata nella finestra di dialogo FedCM. È responsabilità dell'IDP includere i campi richiesti nel token restituito. Prendi in considerazione la richiesta di un "profilo di base" in OpenID Connect rispetto agli "ambiti" in OAuth.

Messaggio di informativa in modalità widget.
Messaggio di informativa in modalità widget.
Messaggio di informativa in modalità pulsante.
Messaggio di informativa in modalità pulsante.

Per utilizzare l'API Fields, aggiungi i parametri alla proprietà fields come array nella chiamata navigator.credentials.get(). Per il momento i campi possono contenere 'name', 'email' e 'picture', ma in futuro potranno essere ampliati per includere altri valori.

Una richiesta con fields avrà il seguente aspetto:

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: ['name', 'email', 'picture'],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    },
  }
  mediation: 'optional',
});

La richiesta HTTP all'endpoint di affermazione dell'identità include il parametro fields specificato dall'RP, con il parametro disclosure_text_shown impostato su true se non si tratta di un utente di ritorno, e i campi che il browser ha comunicato all'utente in un parametro disclosure_shown_for:

POST /id_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=true&fields=email,name,picture&disclosure_shown_for=email,name,picture

Se l'RP ha bisogno di accedere ad altri dati dell'IDP, ad esempio all'accesso a un calendario, questo deve essere gestito con un parametro personalizzato come indicato sopra. L'IdP restituisce un URL continue_on per richiedere l'autorizzazione.

Se fields è un array vuoto, la richiesta avrà il seguente aspetto:

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: [],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    },
  }
  mediation: 'optional',
});

Se fields è un array vuoto, lo user agent salta l'interfaccia utente dell'informativa.

Il messaggio di informativa non viene visualizzato in modalità widget. Nel flusso dei pulsanti, l'interfaccia utente dell'informativa viene saltata completamente.
Il messaggio dell'informativa non viene visualizzato in modalità widget. Nel flusso dei pulsanti, l'UI informativa viene saltata completamente.

Questo accade anche se la risposta dell'endpoint account non contiene un ID cliente corrispondente all'RP in approved_clients.

In questo caso, disclosure_text_shown inviato all'endpoint di affermazione dell'ID è false nel corpo HTTP:

POST /id_assertion_endpoint HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false

Più configURL

Più configURL consentono agli IdP di gestire più file di configurazione per un IdP, specificando accounts_endpoint e login_url nel file .well-known come per i file di configurazione.

Se accounts_endpoint e login_url vengono aggiunti al file well-known, i valori provider_urls vengono ignorati in modo che l'IdP possa supportare più file di configurazione. In caso contrario, provider_urls continuerà a essere applicato in modo da essere compatibile con le versioni precedenti.

Il file well-known che supporta più configURL può avere il seguente aspetto:

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

In questo modo possiamo:

  1. Mantieni la compatibilità con le versioni precedenti e successive dei file noti esistenti e con le versioni precedenti dei browser già implementati.
  2. Avere un numero arbitrario di file di configurazione, purché tutti indichino gli stessi accounts_endpoint e login_url.
  3. Non hanno la possibilità di aggiungere entropia alla richiesta di recupero con credenziali rivolta a accounts_endpoint, poiché deve essere specificata a livello di ".well-known".

Il supporto di più configURL è facoltativo e le implementazioni FedCM esistenti possono rimanere invariate.

Etichette account personalizzate

Le Etichette account personalizzate consentono agli identity provider FedCM di annotare gli account in modo che gli RP possano filtrarli specificando l'etichetta in un file di configurazione. È stato possibile applicare un filtraggio simile utilizzando l'API Domain Hint e l'API Login Hint specificandoli nella chiamata navigator.credentials.get(), ma le etichette account personalizzate possono filtrare gli utenti specificando il file di configurazione, il che è particolarmente utile quando vengono utilizzati più configURL. Le etichette account personalizzate sono diverse anche perché vengono fornite dal server dell'IDP, anziché dall'RP, come le indicazioni per l'accesso o il dominio.

Esempio

Un provider di identità supporta due configURL rispettivamente per i clienti consumer ed enterprise. Il file di configurazione consumer ha un'etichetta 'consumer' e il file di configurazione enterprise ha un'etichetta 'enterprise'.

Con questa configurazione, il file well-known include accounts_endpoint e login_url per consentire più configURL.

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

Quando accounts_endpoint viene fornito nel file well-known, i valori provider_urls vengono ignorati. L'RP può puntare direttamente ai rispettivi file di configurazione nella chiamata navigator.credentials.get().

Il file di configurazione del consumatore si trova in https://idp.example/fedcm.json e include la proprietà accounts che specifica 'consumer' utilizzando include.

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "consumer"
  }
}

Il file di configurazione di Enterprise si trova in https://idp.example/enterprise/fedcm.json, che include la proprietà accounts che specifica 'enterprise' utilizzando include.

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/enterprise/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "enterprise"
  }
}

L'endpoint account IdP comune (in questo esempio https://idp.example/accounts) restituisce un elenco di account che include una proprietà di etichette con labels assegnato in un array per ogni account. Di seguito è riportato un esempio di risposta per un utente con due account. Uno è per consumer e l'altro per le aziende:

{
 "accounts": [{
   "id": "123",
   "given_name": "John",
   "name": "John Doe",
   "email": "john_doe@idp.example",
   "picture": "https://idp.example/profile/123",
   "labels": ["consumer"]
  }], [{
   "id": "4567",
   "given_name": "Jane",
   "name": "Jane Doe",
   "email": "jane_doe@idp.example",
   "picture": "https://idp.example/profile/4567",
   "labels": ["enterprise"]
  }]
}

Quando un RP vuole consentire agli utenti 'enterprise' di accedere, può specificare il valore 'enterprise' configURL 'https://idp.example/enterprise/fedcm.json' nella chiamata navigator.credentials.get():

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      clientId: '1234',
      nonce: '234234',
      configURL: 'https://idp.example/enterprise/fedcm.json',
    },
  }
});

Di conseguenza, l'utente può accedere solo con l'ID account '4567'. L'ID account '123' viene nascosto silenziosamente dal browser in modo che all'utente non venga fornito un account non supportato dall'IDP su questo sito.

Prova dell'origine: FedCM come indicatore di attendibilità per l'API Accesso allo spazio di archiviazione

In Chrome 126 è iniziata una prova dell'origine di FedCM come indicatore di attendibilità per l'API Accesso allo spazio di archiviazione. Con questa modifica, una precedente concessione di autorizzazione tramite FedCM diventa un motivo valido per approvare automaticamente una richiesta di accesso allo spazio di archiviazione da parte delle API di accesso allo spazio di archiviazione.

Questo è utile quando un iframe incorporato vuole accedere a risorse personalizzate: ad esempio, se idp.example è incorporato in rp.example e deve mostrare una risorsa personalizzata. Se il browser limita l'accesso ai cookie di terze parti, anche se l'utente ha eseguito l'accesso a rp.example utilizzando idp.example con FedCM, l'iframe idp.example incorporato non potrà richiedere risorse personalizzate perché le richieste non includeranno cookie di terze parti.

Per farlo, idp.example deve ottenere un'autorizzazione di accesso allo spazio di archiviazione tramite il suo iframe incorporato nel sito web e questo può essere ottenuto solo tramite una richiesta di autorizzazione.

Con FedCM come indicatore di attendibilità per l'API Storage Access, i controlli delle autorizzazioni dell'API Storage Access non accettano solo la concessione dell'autorizzazione che viene fornita da una richiesta di accesso allo spazio di archiviazione, ma anche la concessione dell'autorizzazione data da una richiesta FedCM.

// In top-level rp.example:

// Ensure FedCM permission has been granted.
const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/fedcm.json',
      clientId: '123',
    }],
  },
  mediation: 'optional',
});

// In an embedded IdP iframe:

// No user gesture is needed to call this, and the call will be auto-granted.
await document.requestStorageAccess();

// This returns `true`.
const hasAccess = await document.hasStorageAccess();

Una volta che l'utente ha eseguito l'accesso con FedCM, l'autorizzazione viene concessa automaticamente, a condizione che l'autenticazione FedCM sia attiva. Ciò significa che, una volta disconnesso l'utente, verrà visualizzata una richiesta di autorizzazione.

Partecipare alla prova dell'origine

Puoi provare il bundle dell'API FedCM Continuation localmente attivando un flag di Chrome chrome://flags#fedcm-authz su Chrome 126 o versioni successive. Puoi anche provare FedCM come indicatore di attendibilità per l'API Accesso allo spazio di archiviazione a livello locale attivando #fedcm-with-storage-access-api su Chrome 126 o versioni successive.

Queste funzionalità sono disponibili anche come prove dell'origine. Origin trials ti consente di provare nuove funzionalità e di fornire feedback sulla loro usabilità, praticità ed efficacia. Per ulteriori informazioni, consulta la guida introduttiva ai trial delle origini.

Per provare la prova dell'origine del pacchetto dell'API FedCM Continuation, crea due token di prova dell'origine:

Se ti interessa abilitare l'API Continuation insieme al flusso di pulsanti, abilita anche la prova dell'origine API per la modalità pulsante:

Per provare FedCM come indicatore di attendibilità per la prova dell'origine dell'API Accesso allo spazio di archiviazione:

La prova dell'origine del bundle dell'API Continuation e il FedCM come indicatore di attendibilità per la prova dell'origine dell'API Accesso allo spazio di archiviazione sono disponibili da Chrome 126.

Registra una prova dell'origine di terze parti per il RP

  1. Vai alla pagina di registrazione della prova di Origin.
  2. Fai clic sul pulsante Registrati e compila il modulo per richiedere un token.
  3. Inserisci l'origine dell'IDP come Origine web.
  4. Seleziona Corrispondenza di terze parti per iniettare il token con JavaScript in altre origini.
  5. Fai clic su Invia.
  6. Incorpora il token emesso su un sito web di terze parti.

Per incorporare il token in un sito web di terze parti, aggiungi il seguente codice alla libreria JavaScript o all'SDK dell'IDP pubblicato dall'origine dell'IDP.

const tokenElement = document.createElement('meta');
tokenElement.httpEquiv = 'origin-trial';
tokenElement.content = 'TOKEN_GOES_HERE';
document.head.appendChild(tokenElement);

Sostituisci TOKEN_GOES_HERE con il tuo token.