Benutzerauthentifizierung mit Angular 9 und Azure AD B2C

Die Benutzerauthentifizierung gehört zu den immer wiederkehrenden Aufgaben in der Anwendungsentwicklung, die mittlerweile von vielen Komponenten und Paketen unterstützt wird. In den letzten Jahren haben sich in diesem Bereich OAuth2 und OpenID als weit verbreitete Standards durchgesetzt. Azure AB B2C unterstützt diese Standards und wird - im Gegensatz zum klassischen Azure AD - vor allem in B2C-Szenarien genutzt, um Benutzeraccounts zu verwalten und die zugehörigen Aufgaben in Form von konfigurierbaren User Flows abzubilden. Außerdem können verschiedene weitere Identitätsanbieter, beispielsweise Microsoft Accounts, integriert werden.

Um die Benutzeranmeldung über einen Azure AD B2C Mandanten in einer Angular 9-Anwendung einzurichten, sind einige Schritte erforderlich, die wir im Folgenden beschreiben.

Nachdem der Azure AD B2C-Mandant grundlegend eingerichtet ist, also zumindest der relevante User Flow für Signup und Signin aufgesetzt ist, muss eine neue Anwendungregistrierung für die Angular-Anwendung in Azure AD B2C vorgenommen werden.

Registrierung der Anwendung

Hierzu nutzen wird die neue Benutzeroberfläche, die unter App Registrations zu erreichen ist. Nach einem Klick auf New registration wird die Oberfläche zur Registrierung der Applikation angezeigt:

Registrierung der Anwendung

In unserem Beispiel nennen wir die Anwendung "Angular 9 Demo" und erlauben den Zugriff für beliebige Accounts. Wichtig ist die Einstellung der Redirect URI. Hier wählen wir den Typ "Single-page application (SPA)" aus und geben als Redirect URI * http://localhost:4200/index.html* an. Diese URI ist für Entwicklungszwecke vorerst ausreichend; nach einem Deployment auf einen Server müssten wir hier eine weitere für diesen hinzufügen, damit die Anmeldung funktioniert.

Im Anschluss wird ein Überblick über die Anwendungseinstellungen angezeigt. Hier ist insbesondere die Client-ID wichtig, die wir im weiteren Verlauf brauchen und deshalb gleich kopieren sollten:

Client ID

Damit wir den empfohlenen Authorization Code Flow mit PKCE nutzen können, müssen wir die Anwendung noch als öffentliche Anwendung kennzeichnen - ansonsten wäre die Angabe eines Client Secrets notwendig, das wir in der Angular-Anwendung jedoch nicht geheim halten können. Dazu wechseln wir auf die Ansicht Authentication. Im unteren Bereich ist die Einstellung Treat application as a public client zu finden, die wir aktivieren müssen:

Public Client

Damit sind die Vorbereitungen in Azure AD B2C vorerst abgeschlossen und wir können die OpenID-Konfiguration abfragen.

OpenID-Konfiguration abfragen

Zur Vorbereitung der Integration in die Angular-Anwendung fragen wir die OpenID-Konfiguration ab, um wichtige Einstellungen parat zu haben. Diese können wir unter folgender URL erreichen:

https://***b2c-tenant-name***.b2clogin.com/b2c-tenant-name***.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=***user-flow-name***

Die Platzhalter ***b2c-tenant-name*** und ***user-flow-name*** müssen auf die Umgebung angepasst werden. Das Ergebnis sieht in etwa so aus:

{
  "issuer": "https://***",
  "authorization_endpoint": "https://***",
  "token_endpoint": "https://***",
  "end_session_endpoint": "https://***",
  "jwks_uri": "https://***"
  // ...
}

Diese Werte sollten wir parat haben, um sie später in die Konfiguration aufnehmen zu können.

Einrichtung der Authentifizierung in Angular

Es gibt eine Vielzahl an Bibliotheken, um eine OpenID-konforme Benutzeranmeldung in Angular zu integrieren. In diesem Beispiel nutzen wir das Package angular-oauth2-oidc von Manfred Steyer. Dieses ist OpenID-zertifiziert und unter MIT-Lizenz verfügbar:

npm i angular-oauth2-oidc --save

Im Anschluss wird das NgModule in der app.module.ts importiert:

// ...
import { OAuthModule } from 'angular-oauth2-oidc';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    // ...
    OAuthModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Danach legen wir eine Datei auth.config.ts an, die die Einstellungen zur Authentifizierung enthalten wird. Die Datei auth.config.ts hat anschließend mindestens folgenden Inhalt:

import { AuthConfig } from 'angular-oauth2-oidc';

export const DiscoveryDocumentConfig = {
    url: "https://***"
}

export const authConfig: AuthConfig = {
    redirectUri: window.location.origin + '/index.html',
    responseType: 'code',
    issuer: 'https://***',
    strictDiscoveryDocumentValidation: false,
    tokenEndpoint: 'https://***',
    loginUrl: 'https://***',
    clientId: '***',
    scope: 'openid profile'
}

Die einzelnen Einstellungen nehmen wir folgendermaßen vor:

  • Die Discovery-URL können wir von vorhin weiter verwenden
  • Den Issuer, den tokenEndpoint und die loginUrl finden wir im Discovery-Dokument.
  • Die clientId haben wir uns schon im ersten Schritt gemerkt.
  • Außerdem ist wichtig, dass auf die strikte Validierung des Discovery-Dokuments verzichtet wird (strictDiscoveryDocumentValidation), weil ansonsten Fehler gemeldet werden, weil alle URLs im Discovery-Dokument mit der Issuer-Url beginnen müssen.

Anschließend können wir in der app.component.ts mit dem Initialisieren der Authentifizierung beginnen. In einer minimalen Variante ist die Datei folgendermaßen aufgebaut:

import { Component } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { authConfig, DiscoveryDocumentConfig } from './auth.config';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'Azure AD B2C with Angular 9';
  constructor(private oauthService: OAuthService) {
    this.oauthService.configure(authConfig);
    this.oauthService.loadDiscoveryDocument(DiscoveryDocumentConfig.url);
    this.oauthService.tryLoginCodeFlow();
  }

  public login() {
    this.oauthService.initCodeFlow();
  }

  public logout() {
    this.oauthService.logOut();
  }

  public get claims(): any {
    return this.oauthService.getIdentityClaims();
  }
}

Im Konstruktor wird zunächst die Konfiguration vorgenommen und anschließend das Discovery-Dokumente geladen. Durch den Aufruf von tryLoginCodeFlow wird beim Start geprüft, ob ein Code vorhanden ist und dieser in ein Token umgewandelt.

Die Methode login enthält die Anweisungen, durch die die Anmeldung gestartet wird. In unserem Beispiel wird diese durch einen Button-Click aufgerufen. Die get-Methode claims holt die Claims, die im Token vorhanden sind; diese können genutzt werden, um weitere Informationen zum Benutzer zu erhalten, die von Azure AD B2C im Token übermittelt wurden.

Nächste Schritte

Dieses Beispiel zeigt, dass auf einfache Weise eine Benutzeranmeldung mit Azure AD B2C in einer Angular 9-Anwendung vorgenommen werden kann. Über Guards können darüber hinaus bestimmte Routen abgesichert werden, so dass für diese eine Benutzeranmeldung erforderlich ist. Hierfür gibt es eine Sample-Anwendung.

Natürlich ist die Angular-Anwendung nur eine Seite der Medaille. Mindestens genauso wichtig ist natürlich, die APIs, die von der Anwendung verwendet werden, ebenfalls abzusichern. Wie dies geht, zeigen wir in einem zukünftigen Post.


Online-Programm

Basierend auf unserer langjährigen Erfahrung im Developer Coaching haben wir folgendes Programm für Sie zusammengestellt:

Professional .NET-Developer Programm

.NET & .NET Core Projekte durch bewährte Vorgehensweisen und stabile Strukturen erfolgreich meistern

Nächster Lauf ab 04.11.2020