Accesso dell'applicazione a pagina singola usando il flusso implicito OAuth 2.0 in Azure Active Directory B2C
Molte applicazioni moderne hanno un front-end di app a pagina singola (SPA) scritto principalmente in JavaScript. Spesso l'app viene scritta usando un framework come React, Angular o Vue.js. Gli spA e altre app JavaScript che vengono eseguite principalmente in un browser presentano alcune sfide aggiuntive per l'autenticazione:
Le caratteristiche di sicurezza di queste app sono diverse dalle applicazioni Web basate su server tradizionali.
Molti server di autorizzazione e provider di identità non supportano richieste CORS (Cross-Origin Resource Sharing).
Il browser a pagina intera reindirizza dall'app può essere invasivo per l'esperienza utente.
Il modo consigliato per supportare gli SPA è il flusso di codice di autorizzazione OAuth 2.0 (con PKCE).
Alcuni framework, come MSAL.js 1.x, supportano solo il flusso di concessione implicita. In questi casi, Azure Active Directory B2C (Azure AD B2C) supporta il flusso di concessione implicita dell'autorizzazione OAuth 2.0. Il flusso è descritto nella sezione 4.2 della specifica OAuth 2.0. Nel flusso implicito, l'app riceve i token direttamente dall'endpoint di autorizzazione B2C di Azure AD, senza alcun scambio da server a server. Tutte le operazioni di gestione delle sessioni e della logica di autenticazione vengono eseguite interamente nel client JavaScript con un reindirizzamento di pagina o una casella popup.
Azure AD B2C estende il flusso implicito OAuth 2.0 standard e va oltre le semplici operazioni di autorizzazione e autenticazione. Azure AD B2C introduce il parametro di criteri. Con il parametro di criteri è possibile usare OAuth 2.0 per aggiungere criteri all'app, ad esempio i flussi utente di iscrizione, accesso e gestione dei profili. Nell'esempio di richieste HTTP in questo articolo viene usato {tenant}.onmicrosoft.com per l'illustrazione. Sostituire {tenant}
con il nome del tenant se ne hai uno. È inoltre necessario creare un flusso utente.
Viene usata la figura seguente per illustrare il flusso di accesso implicito. Ogni passaggio verrà descritto in dettaglio più avanti nell'articolo.
Invio di richieste di autenticazione
Quando l'applicazione Web deve autenticare l'utente ed eseguire un flusso utente, indirizza l'utente all'endpoint di /authorize
Azure AD B2C. L'utente esegue l'azione a seconda del flusso utente.
In questa richiesta, il client indica le autorizzazioni che deve acquisire dall'utente nel scope
parametro e dal flusso utente da eseguire. Per ottenere un'idea del funzionamento della richiesta, provare a incollarla in un browser ed eseguirla. Sostituire:
{tenant}
con il nome del tenant di Azure AD B2C.90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
con l'ID app dell'applicazione registrata nel tenant.{policy}
con il nome di un criterio creato nel tenant, ad esempiob2c_1_sign_in
.
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=id_token+token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&response_mode=fragment
&scope=openid%20offline_access
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345
I parametri nella richiesta HTTP GET sono illustrati nella tabella seguente.
Parametro | Obbligatoria | Descrizione |
---|---|---|
{tenant} | Sì | Nome del tenant di Azure AD B2C |
{policy} | Sì | Nome del flusso utente da eseguire. Specificare il nome di un flusso utente creato nel tenant di Azure AD B2C. Ad esempio: b2c_1_sign_in , b2c_1_sign_up o b2c_1_edit_profile . |
client_id | Sì | ID applicazione assegnato all'applicazione portale di Azure. |
response_type | Sì | Deve includere id_token per l'accesso a OpenID Connect. Può includere anche il tipo di token risposta . Se si usa token , l'app può ricevere immediatamente un token di accesso dall'endpoint di autorizzazione senza dover inviare una seconda richiesta a tale endpoint. Se si usa il tipo di risposta token , il parametro scope deve contenere un ambito che indica la risorsa per cui emettere il token. |
redirect_uri | No | URI di reindirizzamento dell'app dove le risposte di autenticazione possono essere inviate e ricevute dall'app. Deve corrispondere esattamente a uno degli URI di reindirizzamento aggiunti a un'applicazione registrata nel portale, ad eccezione del fatto che deve essere codificato con URL. |
response_mode | No | Specifica il metodo da usare per restituire il token risultante all'app. Per i flussi impliciti, usare fragment . |
ambito | Sì | Elenco di ambiti separato da spazi. Un singolo valore di ambito indica Microsoft Entra ID entrambe le autorizzazioni richieste. L'ambito openid indica un'autorizzazione per l'accesso dell'utente e per ottenere i dati relativi all'utente sotto forma di token ID. L’ambito offline_access è facoltativo per le applicazioni Web. Indica che l'app necessita di un token di aggiornamento per avere un accesso duraturo alle risorse. |
state | No | Valore incluso nella richiesta che viene anche restituito nella risposta del token. Può trattarsi di una stringa di qualsiasi contenuto si voglia usare. Per evitare attacchi di richiesta intersito falsa, viene in genere usato un valore univoco generato casualmente. Lo stato viene usato anche per codificare informazioni sullo stato dell'utente nell'app prima che si sia verificata la richiesta di autenticazione, ad esempio la pagina in cui l'utente è stato attivato o il flusso utente in esecuzione. |
nonce | Sì | Valore incluso nella richiesta, generata dall'app, che viene incorporato nel token ID risultante come attestazione. L'app può quindi verificare questo valore per l'attenuazione degli attacchi di riproduzione del token. Il valore è in genere una stringa casuale univoca che può essere usata per identificare l'origine della richiesta. |
prompt | No | Tipo di interazione utente obbligatoria. Al momento l'unico valore valido è login . Questo parametro impone all'utente di immettere le proprie credenziali in tale richiesta. La singola Sign-On non ha effetto. |
Questa è la parte interattiva del flusso. L'utente viene chiesto di completare il flusso di lavoro del criterio. L'utente potrebbe dover immettere il nome utente e la password, accedere con un'identità social, iscriversi a un account locale o qualsiasi altro numero di passaggi. Le azioni dell'utente dipendono dal modo in cui è definito il flusso utente.
Al termine del flusso utente, Azure AD B2C restituisce una risposta all'app tramite redirect_uri
. Viene usato il metodo specificato nel parametro response_mode
. La risposta è esattamente la stessa per ogni scenario di azione dell'utente, indipendentemente dal flusso utente eseguito.
Risposta di esito positivo
Una risposta con esito positivo che usa response_mode=fragment
e response_type=id_token+token
è simile a quanto riportato di seguito. Sono state aggiunte interruzioni di riga per migliorare la leggibilità:
GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&token_type=Bearer
&expires_in=3599
&scope="90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 offline_access",
&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
Parametro | Descrizione |
---|---|
access_token | Token di accesso richiesto dall'app da Azure AD B2C. |
token_type | Valore del tipo di token. L'unico tipo supportato da Azure AD B2C è Bearer. |
expires_in | Periodo di validità del token di accesso (in secondi). |
ambito | Ambiti per i quali il token è valido. È possibile usare gli ambiti anche per memorizzare i token nella cache per un uso successivo. |
id_token | Token ID richiesto dall'app. È possibile usare il token ID per verificare l'identità dell'utente e avviare una sessione con l'utente. Per informazioni dettagliate sui token ID e sul relativo contenuto, vedere Azure AD B2C: informazioni di riferimento sui token. |
state | Se nella richiesta è incluso un parametro state , lo stesso valore deve essere visualizzato nella risposta. L'app deve verificare che i valori state nella richiesta e nella risposta siano identici. |
Risposta di errore
Anche le risposte di errore possono essere inviate all'URI di reindirizzamento in modo che l'app possa gestirle adeguatamente:
GET https://aadb2cplayground.azurewebsites.net/#
error=access_denied
&error_description=the+user+canceled+the+authentication
&state=arbitrary_data_you_can_receive_in_the_response
Parametro | Descrizione |
---|---|
error | Codice utilizzato per classificare i tipi di errori che si verificano. |
error_description | Messaggio di errore specifico che consente di identificare la causa principale di un errore di autenticazione. |
state | Se nella richiesta è incluso un parametro state , lo stesso valore deve essere visualizzato nella risposta. L'app deve verificare che i valori state nella richiesta e nella risposta siano identici. |
Convalidare il token ID
La ricezione di un token ID non è sufficiente per autenticare l'utente. Convalidare la firma del token ID e verificare le attestazioni nel token in base ai requisiti dell'app. Azure AD B2C usa token JSON Web (JWT) e crittografia a chiave pubblica per firmare i token e verificare che siano validi.
Sono disponibili molte librerie open source per la convalida dei token JWT, a seconda del linguaggio preferito. È consigliabile prendere in esame le librerie open source disponibili anziché implementare una logica di convalida personalizzata. È possibile usare le informazioni contenute in questo articolo permettono di imparare a usare correttamente tali librerie.
Azure AD B2C include un endpoint dei metadati di OpenID Connect. Un'app può usare l'endpoint per recuperare informazioni su Azure AD B2C in fase di esecuzione. Queste informazioni includono endpoint, contenuti del token e chiavi per la firma dei token. Il tenant Azure AD B2C include un documento di metadati JSON per ogni flusso utente. Ad esempio, il documento di metadati per un flusso utente denominato b2c_1_sign_in
in un fabrikamb2c.onmicrosoft.com
tenant si trova in:
https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/v2.0/.well-known/openid-configuration
Una proprietà di questo documento di configurazione è jwks_uri
. Il valore per lo stesso flusso utente sarà:
https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/discovery/v2.0/keys
Per determinare il flusso utente usato per firmare un token ID (e da dove recuperare i metadati), è possibile usare una delle opzioni seguenti:
Il nome del flusso utente è incluso nell'attestazione
acr
inid_token
. Per informazioni su come analizzare le attestazioni da un token ID, vedere Azure AD B2C: informazioni di riferimento sui token.Codificare il flusso utente nel valore del
state
parametro quando si esegue la richiesta. per poi decodificare il parametrostate
e determinare il flusso utente usato.
Dopo aver acquisito il documento dei metadati dall'endpoint di metadati OpenID Connect, è possibile usare le chiavi pubbliche RSA 256 che si trovano in questo endpoint per convalidare la firma del token ID. In un determinato punto nel tempo è possibile che siano presenti più chiavi elencate in questo endpoint, ognuna identificata da un'attestazione kid
. Anche l'intestazione di id_token
contiene un'attestazione kid
, che indica le chiavi usate per firmare il token ID. Per altre informazioni, inclusa la convalida dei token, vedere Azure AD B2C: informazioni di riferimento sui token.
Dopo la convalida della firma del token ID sarà necessario verificare anche diverse altre attestazioni, Ad esempio:
Convalidare l'attestazione
nonce
per impedire attacchi di riproduzione dei token. Il valore deve corrispondere a quello specificato nella richiesta di accesso.Convalidare l'attestazione
aud
per verificare che il token ID sia stato emesso per l'app. Il valore deve essere l'ID applicazione dell'app.Convalidare le attestazioni
iat
eexp
per verificare che il token ID non sia scaduto.
Altre convalide da eseguire sono descritte in dettaglio nella specifica OpenID Connect Core. È anche possibile convalidare attestazioni aggiuntive, a seconda dello scenario. Alcune convalide comuni includono:
Verificare che l'utente o l'organizzazione abbia eseguito l'iscrizione all'app.
Verificare che l'utente abbia le autorizzazioni e i privilegi adeguati.
Garantire che si sia verificata una certa forza di autenticazione, ad esempio usando Microsoft Entra'autenticazione a più fattori.
Per altri dettagli sulle attestazioni in un token ID, vedere Azure AD B2C: informazioni di riferimento sui token.
Dopo aver convalidato il token ID, è possibile iniziare una sessione con l'utente. Usare nell'app le attestazioni del token ID per ottenere informazioni sull'utente. Queste informazioni possono essere usate per la visualizzazione, i record, le autorizzazioni e così via.
Ottenere i token di accesso
Se l'app Web deve solo eseguire flussi utente, è possibile saltare le prossime sezioni. Le informazioni nelle sezioni seguenti sono applicabili solo alle app Web che devono effettuare chiamate autenticate a un'API Web protetta da Azure AD B2C stesso.
Ora che l'utente è stato connesso all'applicazione a pagina singola, è possibile ottenere i token di accesso per chiamare le API Web protette da Microsoft Entra ID. Anche se è già stato ricevuto un token usando il token
tipo di risposta, è possibile usare questo metodo per acquisire token per risorse aggiuntive senza reindirizzare l'utente all'accesso.
In un flusso tipico dell'app Web è necessario effettuare una richiesta all'endpoint /token
. Tuttavia, l'endpoint non supporta le richieste CORS, quindi l'esecuzione di chiamate AJAX per ottenere un token di aggiornamento non è un'opzione. È possibile usare invece il flusso implicito in un elemento iframe HTML nascosto per ottenere nuovi token per altre API Web. Di seguito è riportato un esempio, con le interruzioni di riga per migliorare la leggibilità:
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
&response_mode=fragment
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345
&prompt=none
Parametro | Necessaria? | Descrizione |
---|---|---|
{tenant} | Necessario | Nome del tenant di Azure AD B2C |
{policy} | Necessario | Flusso utente da eseguire. Specificare il nome di un flusso utente creato nel tenant di Azure AD B2C. Ad esempio: b2c_1_sign_in , b2c_1_sign_up o b2c_1_edit_profile . |
client_id | Necessario | ID applicazione assegnato all'app nel portale di Azure. |
response_type | Obbligatoria | Deve includere id_token per l'accesso a OpenID Connect. Può anche includere il tipo di risposta token . Se si usa token in questo momento, l'app può ricevere immediatamente un token di accesso dall'endpoint di autorizzazione senza dover inviare una seconda richiesta a tale endpoint. Se si usa il tipo di risposta token , il parametro scope deve contenere un ambito che indica la risorsa per cui emettere il token. |
redirect_uri | Consigliato | URI di reindirizzamento dell'app dove le risposte di autenticazione possono essere inviate e ricevute dall'app. Deve corrispondere esattamente a uno degli URI di reindirizzamento registrati nel portale, ad eccezione del fatto che deve essere codificato come URL. |
ambito | Necessario | Elenco di ambiti separati da spazi. Per ottenere i token, includere tutti gli ambiti necessari per la risorsa di interesse. |
response_mode | Consigliato | Specifica il metodo usato per restituire il token risultante all'app. Per il flusso implicito, usare fragment . È possibile specificare query altre due modalità e form_post , ma non funzionano nel flusso implicito. |
state | Consigliato | Valore incluso nella richiesta che viene restituito nella risposta del token. Può trattarsi di una stringa di qualsiasi contenuto si voglia usare. Per evitare attacchi di richiesta intersito falsa, viene in genere usato un valore univoco generato casualmente. Anche lo stato viene usato per codificare le informazioni sullo stato dell'utente nell'app prima del verificarsi della richiesta di autenticazione, ad esempio, la pagina o la vista in cui si trovava l'utente. |
nonce | Necessario | Valore incluso nella richiesta, generato dall'app inclusa nel token ID risultante come attestazione. L'app può quindi verificare questo valore per l'attenuazione degli attacchi di riproduzione del token. Il valore è in genere una stringa casuale univoca che identifica l'origine della richiesta. |
prompt | Necessario | Per aggiornare e ottenere i token in un iframe nascosto, usare prompt=none per assicurarsi che l'iframe non si blocchi nella pagina di accesso e restituisca immediatamente. |
login_hint | Necessario | Per aggiornare e ottenere token in un iframe nascosto, includere il nome utente dell'utente in questo hint per distinguere tra più sessioni che l'utente potrebbe avere in un determinato momento. È possibile estrarre il nome utente da un accesso precedente usando l'attestazione preferred_username (l'ambito è necessario per ricevere l'attestazione profile preferred_username ). |
domain_hint | Necessario | Può essere consumers o organizations . Per aggiornare e ottenere token in un iframe nascosto, includere il domain_hint valore nella richiesta. Estrarre l'attestazione tid dal token ID di un accesso precedente per determinare quale valore usare (l'ambito è necessario per ricevere l'attestazione tid profile ). Se il valore dell'attestazione tid è 9188040d-6c67-4c5b-b112-36a304b66dad , usare domain_hint=consumers . In caso contrario, usare domain_hint=organizations . |
Impostando il parametro prompt=none
, la richiesta ha immediatamente esito positivo o negativo e torna all'applicazione. Una risposta riuscita viene inviata all'app tramite l'URI di reindirizzamento usando il metodo specificato nel response_mode
parametro .
Risposta di esito positivo
Una risposta con esito positivo usando response_mode=fragment
è simile all'esempio seguente:
GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
&token_type=Bearer
&expires_in=3599
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
Parametro | Descrizione |
---|---|
access_token | Token richiesto dall'app. |
token_type | Il tipo di token sarà sempre una connessione. |
state | Se nella richiesta è incluso un parametro state , lo stesso valore deve essere visualizzato nella risposta. L'app deve verificare che i valori state nella richiesta e nella risposta siano identici. |
expires_in | Tempo di validità del token di accesso (in secondi). |
ambito | Ambiti per i quali il token di accesso è valido. |
Risposta di errore
Anche le risposte di errore possono essere inviate all'URI di reindirizzamento in modo che l'app possa gestirle adeguatamente. Per prompt=none
, un errore previsto è simile all'esempio seguente:
GET https://aadb2cplayground.azurewebsites.net/#
error=user_authentication_required
&error_description=the+request+could+not+be+completed+silently
Parametro | Descrizione |
---|---|
error | Stringa di codice di errore che può essere usata per classificare i tipi di errore che si verificano. È possibile usare la stringa anche per rispondere agli errori. |
error_description | Messaggio di errore specifico che consente di identificare la causa principale di un errore di autenticazione. |
Se si riceve questo errore nella richiesta iframe, l'utente deve accedere di nuovo in modo interattivo per recuperare un nuovo token.
Token di aggiornamento
Token ID e token di accesso scadono entrambi dopo un breve periodo di tempo. L'app deve essere predisposta ad aggiornare periodicamente questi token. I flussi impliciti non consentono di ottenere un token di aggiornamento a causa di motivi di sicurezza. Per aggiornare uno dei tipi di token, usare il flusso implicito in un elemento iframe HTML nascosto. Nella richiesta di autorizzazione includere il prompt=none
parametro . Per ricevere un nuovo valore id_token, assicurarsi di usare response_type=id_token
e scope=openid
e un nonce
parametro .
Inviare una richiesta di disconnessione
Quando si vuole disconnettere l'utente dall'app, reindirizzare l'utente all'endpoint di disconnessione di Azure AD B2C. È quindi possibile cancellare la sessione dell'utente nell'app. Se non si reindirizza l'utente, potrebbe essere possibile ripetere l'autenticazione all'app senza immettere di nuovo le credenziali perché ha una sessione single Sign-On valida con Azure AD B2C.
È sufficiente reindirizzare l'utente all'oggetto end_session_endpoint
elencato nello stesso documento dei metadati di OpenID Connect descritto in Convalidare il token ID. Ad esempio:
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
Parametro | Obbligatoria | Descrizione |
---|---|---|
{tenant} | Sì | Nome del tenant di Azure AD B2C. |
{policy} | Sì | Flusso utente da usare per disconnettere l'utente dall'applicazione. Deve essere lo stesso flusso utente usato dall'app per accedere all'utente. |
post_logout_redirect_uri | No | URL a cui l'utente deve essere reindirizzato dopo la disconnessione. Se non è incluso, Azure AD B2C mostra all'utente un messaggio generico. |
state | No | Se nella richiesta è incluso un parametro state , lo stesso valore deve essere visualizzato nella risposta. L'applicazione deve verificare che i state valori nella richiesta e nella risposta siano identici. |
Nota
Indirizzando l'utente allo end_session_endpoint
stato Single Sign-On dell'utente con Azure AD B2C. l'utente non viene disconnesso dalla sessione del provider di identità basato su social network. Se l'utente seleziona lo stesso provider di identità durante un accesso successivo, l'utente viene autenticato nuovamente, senza immettere le credenziali. Se un utente vuole disconnettersi dall'applicazione Azure AD B2C, non significa necessariamente che voglia disconnettersi completamente dal proprio account Facebook, ad esempio. Tuttavia, per gli account locali, la sessione dell'utente viene terminata in modo corretto.
Passaggi successivi
Vedere l'esempio di codice: Accedere con Azure AD B2C in un'applicazione a pagina singola JavaScript.