AngularAtlasAusg. 22.2

Kap. 17Sicherheit & Globalisierung73 / 75

Authentifizierung: Tokens & Refresh

Ein Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.

~0 Min. Lesezeit Offizielle Doku

Die meisten Anwendungen verwenden zwei Tokens. Ein kurzlebiges Access-Token (einige Minuten) begleitet jeden Request. Ein langlebiges Refresh-Token liefert ein neues Access-Token, ohne dass sich der Benutzer erneut anmelden muss. Schwierig ist nicht, einen Header anzuhängen, sondern der Moment, in dem das Access-Token abläuft, während schon fünf Requests unterwegs sind.

Die Seite baut Schritt für Schritt einen funktionalen Interceptor, der das Token anhängt, bei einem 401 einen einzigen Refresh ausführt, den alle wartenden Requests teilen, und sie danach erneut sendet. Du siehst außerdem, wo du die Tokens am besten aufbewahrst und was du tust, wenn der Refresh fehlschlägt.

Warum das wichtig ist
Ein naiv geschriebener Auth-Interceptor funktioniert in der Entwicklung einwandfrei, wo du immer nur einen Request auf einmal sendest. In Produktion löst ein Dashboard, das 6 Requests gleichzeitig mit abgelaufenem Token startet, 6 Refreshes aus, Race Conditions zwischen Tokens und – mit „Refresh Token Rotation“ – zufällige Abmeldungen. Der Bug ist schwer zu reproduzieren, aber leicht zu vermeiden.

Der gesamte Ablauf

Das Access-Token reist im Header Authorization: Bearer …. Antwortet der Server mit 401, fragt die Anwendung beim Refresh-Endpoint ein neues Token an. Das Refresh-Token wird nicht aus JavaScript gesendet: Es liegt in einem HttpOnly-Cookie, das der Browser automatisch mitschickt (withCredentials). Danach wird der ursprüngliche Request mit dem neuen Token wiederholt. Für den Benutzer bleibt alles unsichtbar.

browser                         API                              auth server
   │  GET /orders  (Bearer A1)   │                                    │
   │────────────────────────────▶│  A1 abgelaufen → 401               │
   │◀────────────────────────────│                                    │
   │  POST /auth/refresh  (HttpOnly-Cookie mit Refresh-Token)         │
   │─────────────────────────────────────────────────────────────────▶│
   │◀─────────────────────────────────────────── { accessToken: A2 } │
   │  GET /orders  (Bearer A2)   │                                    │
   │────────────────────────────▶│  200                               │

Der Interceptor: ein Refresh gleichzeitig

Drei Details machen den Unterschied:

  1. Der Interceptor hängt das Token nur an die URLs deiner eigenen API an, damit du es nicht an Dritte sendest.
  2. Der Refresh-Request ist mit einem HttpContextToken (SKIP_AUTH) markiert, damit sich der Interceptor nicht endlos selbst abfängt (siehe HttpClient & Interceptors).
  3. Die Session hält den aktuellen Refresh in einem Feld. Der erste 401 startet ihn, und alle anderen abonnieren dasselbe Observable (shareReplay(1)). finalize leert das Feld am Ende.

Es gibt einen subtilen Fall: Ein Request kann einen 401 erhalten, nachdem ein anderer den Refresh bereits abgeschlossen hat. Dann weicht das aktuelle Token vom verwendeten ab, und der Request wird einfach ohne weiteren Refresh wiederholt.

import { HttpContextToken, HttpErrorResponse, HttpInterceptorFn, HttpRequest } from '@angular/common/http';
import { inject } from '@angular/core';
import { catchError, switchMap, throwError } from 'rxjs';

/** Markierte Requests erhalten kein Token und lösen keinen Refresh aus (z. B. Login, Refresh). */
export const SKIP_AUTH = new HttpContextToken<boolean>(() => false);

const withToken = (req: HttpRequest<unknown>, token: string | null) =>
  token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req;

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const session = inject(AuthSession);
  if (req.context.get(SKIP_AUTH) || !req.url.startsWith('/api/')) return next(req); // nur deine API!

  const used = session.token();
  return next(withToken(req, used)).pipe(
    catchError((err: unknown) => {
      if (!(err instanceof HttpErrorResponse) || err.status !== 401) return throwError(() => err);
      // ein anderer Request hat das Token schon erneuert, während dieser unterwegs war → wir wiederholen nur
      if (session.token() && session.token() !== used) return next(withToken(req, session.token()));
      return session.refresh().pipe(switchMap((fresh) => next(withToken(req, fresh))));
    }),
  );
};
LiveFünf Requests mit abgelaufenem Token (echter HttpClient, simulierter Server)
token: acc-1Requests: 0401: 0Refreshes: 0erfolgreich: 0
  1. Drücke 1, dann 2. Das Protokoll zeigt die genaue Reihenfolge der Requests.
Klicke auf „Token ablaufen lassen“ und sende dann die 5 Requests. In der korrekten Variante siehst du 5 × 401, einen einzigen Refresh und 5 erfolgreiche Wiederholungen. Wechsle zu „naiv“ und wiederhole: 5 Refreshes, Tokens, die sich gegenseitig ungültig machen, und fehlschlagende Requests. Setze den Haken bei „der Refresh schlägt fehl“, um den Logout zu sehen.

Das Beispiel hat seinen eigenen HttpClient, erstellt mit createEnvironmentInjector([provideHttpClient(withInterceptors([…]))], …). Seine Interceptors (Auth + ein simulierter „Server“, als Letztes in der Kette) berühren den Rest der Anwendung nicht.

Die naive Variante und warum sie scheitert

Wenn jeder 401 seinen eigenen Refresh auslöst, wächst die Anzahl der Refreshes mit der Anzahl paralleler Requests. Viele Server rotieren das Refresh-Token (jeder Refresh macht das vorherige ungültig), sodass sich gleichzeitige Refreshes gegenseitig aufheben. Manche behandeln die Wiederverwendung eines alten Refresh-Tokens sogar als Angriff und beenden die ganze Session.

// ✗ Die naive Variante: Jeder 401 löst seinen eigenen Refresh aus
catchError((err) =>
  err.status === 401
    ? http.post('/auth/refresh', null).pipe(switchMap((r) => next(withToken(req, r.accessToken))))
    : throwError(() => err),
);
// 5 parallele Requests mit abgelaufenem Token → 5 Refreshes.
// Bei „Refresh Token Rotation“ macht jeder Refresh den vorherigen ungültig → manche Requests schlagen erneut fehl,
// und manche Server werten die Wiederverwendung als Angriff und beenden die ganze Session.

Wo du die Tokens aufbewahrst

Jeder JavaScript-Code auf deiner Seite kann localStorage lesen, auch ein per XSS eingeschleustes Skript (siehe Sicherheit). Ein HttpOnly-Cookie kann nicht aus JavaScript gelesen werden, wird aber automatisch gesendet, daher brauchst du SameSite und XSRF-Schutz. Der übliche Kompromiss: das kurzlebige Access-Token im Speicher (ein Signal), das Refresh-Token in einem HttpOnly-Cookie. Am sichersten ist ein BFF (Backend-for-Frontend): Die OAuth-Tokens bleiben auf dem Server, und der Browser hat nur ein Session-Cookie.

LiveWo bewahrst du das Token auf? Abwägungen
Wenn die Anwendung ein XSS hat es lässt sich nicht direkt lesen, aber eingeschleuster Code kann Requests senden, solange die Seite offen ist
Beim Neuladen der Seite geht verloren → Refresh-Token (Cookie) beim Start
CSRFwird nicht automatisch gesendet → kein CSRF
Mehrere Tabsjeder Tab macht einen eigenen Refresh

empfohlen Gut für das kurzlebige Access-Token, kombiniert mit einem Refresh-Token in einem HttpOnly-Cookie.

Wähle eine Option und vergleiche, was bei XSS, beim Neuladen, bei CSRF und mit mehreren Tabs passiert.

Start, Guards und Tabs

Beim Start der Anwendung fehlt das Access-Token im Speicher. Ein provideAppInitializer versucht vor der ersten Route einen Refresh, damit ein angemeldeter Benutzer die Login-Seite nicht einmal kurz sieht. Der Authentifizierungszustand ist ein Signal, und der funktionale Guard liest es und leitet mit createUrlTree um (siehe Guards & Resolver). Der Logout muss an alle Tabs weitergegeben werden. Ein BroadcastChannel erledigt das in wenigen Zeilen (siehe auch Angular Elements).

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([authInterceptor])),
    provideAppInitializer(() => {
      // beim Start: Liegt ein Refresh-Token im Cookie? Wir holen ein Access-Token vor der ersten Seite
      const session = inject(AuthSession);
      return firstValueFrom(session.refresh()).catch(() => undefined);
    }),
  ],
};

Wann ja, wann nein

Eigenen Interceptor schreiben
  • Dein Backend stellt die Tokens aus (eigenes JWT) und du brauchst nur Anhängen + Refresh.
  • Du willst volle Kontrolle über die Request-Warteschlange und die Fehlerfälle.
  • Du hast ein BFF, und der Interceptor fügt nur withCredentials hinzu und behandelt 401 → Login.
Etwas anderes verwenden
  • OAuth 2 / OpenID Connect mit einem externen Provider (Entra ID, Auth0, Keycloak): Nutze eine zertifizierte OIDC-Bibliothek, die PKCE, Rotation und die Validierungen korrekt umsetzt. Den Flow selbst, Schritt für Schritt und mit echter Kryptografie, zeigt die Seite zu <a href="/oauth-pkce">OAuth 2.1 und PKCE</a>.
  • Anwendungen mit hohen Sicherheitsanforderungen: Wähle ein BFF statt Tokens im Browser.
  • Klassische Cookie-Sessions ohne Tokens: Du brauchst nur XSRF und die Behandlung von 401.

Häufige Stolperfallen

  • Token wird überallhin gesendet: Ein Interceptor ohne URL-Filter hängt Authorization auch an Requests an CDNs oder Drittanbieter-APIs an.
  • Der Interceptor fängt den Refresh ab: Ein 401 beim Refresh startet einen weiteren Refresh, und so weiter. Markiere den Request mit einem HttpContextToken.
  • Der Refresh wird nicht geteilt: N Requests bedeuten N Refreshes (siehe Beispiel).
  • Retry bei jedem Fehler: Nur ein 401 rechtfertigt einen Refresh. Ein 403 bedeutet „du darfst das nicht“, und ein Refresh ändert daran nichts.
  • Ein Logout, der nicht alles aufräumt: Stores, shareReplay-Caches, Daten in localStorage. Der nächste Benutzer desselben Rechners sieht sie.
  • Das JWT im Frontend „der Sicherheit wegen“ dekodieren: Das ist nur informativ (du zeigst den Namen an). Jede Berechtigungsprüfung erfolgt auf dem Server.

Spickzettel

TOKENS      kurzlebiges Access-Token (Minuten) im SPEICHER · langlebiges Refresh-Token in einem HttpOnly + Secure + SameSite Cookie
            oder BFF: Der Browser hat nur ein Session-Cookie, die Tokens bleiben auf dem Server
INTERCEPTOR nur für die URLs deiner API · SKIP_AUTH (HttpContextToken) für Login/Refresh
401         ein Refresh gleichzeitig (shareReplay + finalize) · Retry mit dem neuen Token
            hat sich das Token inzwischen geändert → nur Retry · Refresh schlägt fehl → Logout + Redirect
START       provideAppInitializer: vor der ersten Route einen Refresh versuchen
GUARD       CanActivateFn auf dem isLoggedIn-Signal → createUrlTree(['/login'], { returnUrl })
TABS        BroadcastChannel / das storage-Event für synchronen Logout
NEIN        Token in localStorage ohne CSP · ein eigener Refresh bei jedem 401 · ein Interceptor, der auch den Refresh abfängt

Kap. 17 · 0 von 4 abgeschlossen

Lektion abgeschlossen?

Markiere sie, dann erscheint sie auf deiner Karte: im Inhaltsverzeichnis und auf der Startseite.

Wird automatisch markiert, sobald du die ganze Lektion gelesen hast.

  1. Sicherheit: XSS, Sanitizing & CSP
  2. Authentifizierung: Tokens & Refresh
  3. OAuth 2.1 & OpenID Connect mit PKCE
  4. Internationalisierung (i18n)
Deine ganze Karte ansehen

Alle 75 Seiten · tippen zum Filtern

  • 01Was ist neu in Angular 21 & 22Alle wichtigen Änderungen in v21 und v22 in Kürze, mit Link zur Seite, die sie jeweils erklärt.Start
  • 01Deine erste App, Schritt für SchrittEine Leseliste, von einer leeren Komponente bis zur fertigen App — Signals, @for, Inputs und Outputs, ein Service und ein Formular, Schritt für Schritt.Start
  • 01Schnelle Entscheidungen„Wohin damit?“, „Signal oder Observable?“, „Shared oder Feature?“ — kurze Antworten auf Alltagsfragen.Start
  • 01Angular-Interviewfragen60 echte Interviewfragen für Junior, Mid und Senior, mit der passenden Antwort, der Nachfrage und den Warnsignalen. Dazu ein Probeinterview.Start
  • 02Standalone & BootstrapWie eine App ohne NgModule startet: bootstrapApplication, app.config.ts, imports in der Komponente.Moderne Grundlagen
  • 02Data Binding & EventsInterpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.Moderne Grundlagen
  • 02Control Flow: @if, @for, @switchDie Block-Syntax, die *ngIf/*ngFor/ngSwitch ersetzt, mit track, @empty und Exhaustive Checks.Moderne Grundlagen
  • 02@let und die neuen Template-AusdrückeLokale Variablen mit @let, Arrow Functions, Spread, Regex, instanceof, Kommentare in Tags.Moderne Grundlagen
  • 02@defer — Lazy Loading in TemplatesSchwere Komponenten nur laden, wenn sie gebraucht werden: Trigger, Prefetch, Placeholder, Loading, Error.Moderne Grundlagen
  • 02Class- & Style-BindingsWarum [class.x] und [style.x] ngClass und ngStyle abgelöst haben (mit automatischer Migration ab v21).Moderne Grundlagen
  • 02Komponenten-Styles & Kapselung:host, die drei Kapselungsmodi, Theming mit CSS-Variablen und warum ::ng-deep der letzte Ausweg ist.Moderne Grundlagen
  • 02Pipes: wann und wiePure vs. Impure Pipes, eigene Pipes und wie du zwischen Pipe, computed() und Methode wählst.Moderne Grundlagen
  • 03signal() und computed()Die reaktiven Grundbausteine: beschreibbarer Zustand, abgeleiteter Zustand, Gleichheit, untracked und Regeln zur Immutability.Signals & Reaktivität
  • 03effect() — wann ja, wann neinMit Signals synchronisierte Seiteneffekte: localStorage, Logging, imperative APIs. Und ihre Stolperfallen.Signals & Reaktivität
  • 03linkedSignal() — editierbarer abgeleiteter ZustandEin Signal, das sich zurücksetzt, wenn sich seine Quelle ändert, das du aber auch manuell setzen kannst.Signals & Reaktivität
  • 03resource, rxResource, httpResourceAsynchrone Daten als Signals: status, value, error, reload, automatischer Abbruch. Stabil seit v22.Signals & Reaktivität
  • 03debounced() — verzögerte SignalsDie „Debounce“-Variante eines Signals, ohne RxJS. Perfekt für die Suche.Signals & Reaktivität
  • 03Listen: suchen, filtern, sortieren, blätternEine Kette von computed-Signals, die nur neu berechnet, was sich geändert hat — mit den Filtern in der URL, damit ein Link dieselbe Ansicht öffnet.Signals & Reaktivität
  • 03Observables von null anWas ein Observable ist, subscribe und unsubscribe, die Operatoren, die du jede Woche brauchst, cold vs. hot — und wann ein Signal reicht.Signals & Reaktivität
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — und wann RxJS weiterhin die richtige Wahl bleibt.Signals & Reaktivität
  • 04input() und output()Inputs als Signals (required, transform, alias) und typisierte Outputs. Daten nach unten, Events nach oben.Komponenten: Kommunikation
  • 04model() — Two-Way-BindingBanana-in-a-Box [( )] mit einer einzigen API. Wann du es nutzt und wann input + output besser ist.Komponenten: Kommunikation
  • 04viewChild & contentChildQueries als Signals: viewChild, viewChildren, contentChild, contentChildren, die Option read.Komponenten: Kommunikation
  • 04Lifecycle & DestroyRefWelche Hooks in der Signals-Ära noch zählen, afterNextRender, DestroyRef und typisiertes ngOnChanges.Komponenten: Kommunikation
  • 04Content Projectionng-content mit select, mehrere Slots, Standardinhalt und die Falle der bedingten Projektion.Komponenten: Kommunikation
  • 04ng-template & ngTemplateOutletTemplates als Werte: Render Props in Angular, typisierter Kontext und Anpassen von Komponenten.Komponenten: Kommunikation
  • 05Smart vs. DumbContainer vs. Presentational: wer den Zustand hält, wer nur anzeigt und wie du die beiden sauber trennst.Komponenten-Design
  • 05Generische Komponenten <T>Eine korrekt typisierte DataTable<T> oder Select<T>, mit Templates für Zellen.Komponenten-Design
  • 05Dynamische KomponentenNgComponentOutlet, createComponent mit inputBinding/outputBinding und ein Dashboard, das aus einer Konfiguration gebaut wird.Komponenten-Design
  • 05Direktiven & Host-KompositionAttribut-Direktiven, die host: {}-Metadaten und die Directive Composition API (hostDirectives).Komponenten-Design
  • 05Eigene Formular-ControlsFormValueControl (Signal Forms) vs. ControlValueAccessor: eine Sternebewertung, in beiden Varianten.Komponenten-Design
  • 05Change DetectionOnPush ist ab v22 der Standard, zone.js entfällt ab v21. Was das Rendering auslöst und wie du dir nicht die Finger verbrennst.Komponenten-Design
  • 06inject() & @Service()Der neue @Service()-Decorator ab v22, inject() vs. Konstruktor und der Injection-Kontext.Dependency Injection
  • 06Provider & die Injector-HierarchieRoot vs. Route vs. Komponente, useClass/useValue/useFactory/useExisting und die Modifier optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Typisierte Konfiguration, provideFeature()-Funktionen, makeEnvironmentProviders und Initializer.Dependency Injection
  • 06injectAsync() — Lazy ServicesLade einen schweren Service erst, wenn du ihn brauchst, mit Prefetch im Leerlauf.Dependency Injection
  • 07Ordnerstrukturcore / shared / features, was in welchen Ordner gehört und wie ein Feature von innen aussieht.Architektur der Anwendung
  • 07Shared vs. FeatureWann du eine Komponente nach Shared verschiebst und (vor allem) wann NICHT. Eine konkrete Checkliste.Architektur der Anwendung
  • 07Interfaces & ModelleInline-Interface oder eigene Datei? DTO vs. Domänenmodell, type vs. interface, wohin damit.Architektur der Anwendung
  • 07State Management mit SignalsEinfache Signal-Stores, Fassaden, lokaler vs. globaler Zustand und wann du NgRx brauchst.Architektur der Anwendung
  • 07Styleguide & NamensgebungDie aktuellen offiziellen Konventionen: Dateinamen ohne Suffixe, protected, readonly, Reihenfolge der Member.Architektur der Anwendung
  • 07Barrels, Aliase & Grenzenindex.ts, Pfad-Aliase, die öffentliche API eines Features und Abhängigkeitsregeln, die sich automatisch prüfen lassen.Architektur der Anwendung
  • 07Fehler: @boundary & ErrorHandlerDer neue @boundary-Block ab v22.2, der globale ErrorHandler, HTTP-Fehler und Fehler aus resource.Architektur der Anwendung
  • 08Modernes Routing & Lazy LoadingloadComponent, Child Routes, Parameter als Inputs und Parameter-Vererbung (neuer Standard in v22).Routing
  • 08Guards & ResolvercanActivate, canMatch, canDeactivate und resolve als Funktionen, mit Redirects über UrlTree / RedirectCommand.Routing
  • 09Signal Forms — die GrundlagenFormulare auf Basis von Signals: form(), [formField], schemabasierte Validierung. Stabil seit v22.Formulare
  • 09Signal Forms — fortgeschrittenEigene und feldübergreifende Validierung, async/HTTP mit Debounce, dynamische Listen, disabled/hidden, wiederverwendbare Schemas.Formulare
  • 09Typisierte Reactive FormsTypisierte FormGroup, nonNullable, FormArray — und wie sie neben Signal Forms bestehen.Formulare
  • 10HttpClient, Interceptors & die API-SchichtHttpClient ohne Setup (v21), Fetch als Standard (v22), funktionale Interceptors und eine API-Schicht mit DTO-Mapping.HTTP & Daten
  • 11Performance — eine ChecklisteWas wirklich zählt: OnPush + Signals, track, @defer, Lazy Routes, Bilder, Bundles und Hydration.Qualität & Performance
  • 11Testen mit VitestVitest ist ab v21 der Standard-Runner. TestBed, Komponenten mit Signals, Services, HTTP und Harnesses.Qualität & Performance
  • 11DevTools: ein Blick in deine AppChrome DevTools und Angular DevTools Schritt für Schritt: was jedes Panel zeigt, mit Übungen, die auf dieser Website funktionieren.Qualität & Performance
  • 11Angular AriaHeadless, barrierefreie Komponenten, die du nach Belieben stylst: Tabs, Accordion, Menü, Listbox...Qualität & Performance
  • 12SSR, Prerendering & Render ModesWann auf dem Server gerendert wird, wann beim Build und wann nur im Browser: RenderMode pro Route, app.routes.server.ts und die echten Kosten.SSR & Hydration
  • 12Hydration: Event Replay & inkrementellWie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.SSR & Hydration
  • 12Servertauglicher Codewindow gibt es auf dem Server nicht: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, der HTTP-Cache und PendingTasks.SSR & Hydration
  • 13Micro FrontendsWann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.Architektur im großen Maßstab
  • 13Web Components mit Angular ElementscreateCustomElement: eine Angular-Komponente, die überall als HTML-Tag nutzbar ist, plus Kommunikation zwischen Apps über Events und BroadcastChannel.Architektur im großen Maßstab
  • 13Monorepo, Bibliotheken & GrenzenEin Workspace mit mehreren Apps und Bibliotheken: ng generate library, Nx, Secondary Entry Points, Publishing und Abhängigkeitsregeln.Architektur im großen Maßstab
  • 13Hexagonale Architektur (Ports & Adapters)Eine Domäne ohne Angular, Ports als abstrakte Klassen und austauschbare Adapter: HTTP, localStorage oder In-Memory, ohne die UI anzufassen.Architektur im großen Maßstab
  • 14Signals unter der HaubeDer reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.Fortgeschrittene Reaktivität
  • 14Fortgeschrittenes RxJS: Operatoren höherer OrdnungswitchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.Fortgeschrittene Reaktivität
  • 14NgRx SignalStoreState Management im großen Stil auf Signals: withState, withComputed, withMethods, rxMethod, Entities und Hooks — und wann ein einfacher Store reicht.Fortgeschrittene Reaktivität
  • 14Zustandsautomaten mit SignalsKeine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.Fortgeschrittene Reaktivität
  • 15WebSockets: Echtzeit, die das Netz überstehtEin typisierter Socket als Signals: Reconnect mit Backoff und Jitter, Heartbeat, ein Postausgang im Offline-Modus und SSR-Sicherheit.Echtzeit & offline
  • 15Optimistische Updates & RollbackEine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.Echtzeit & offline
  • 15Offline-first: Service Worker & CachingDer Angular Service Worker: Caching-Strategien, Update-Hinweise und ein Postausgang für Änderungen, die offline entstehen.Echtzeit & offline
  • 16Web WorkersSchwere Berechnungen, ohne die UI zu blockieren: ein echter Worker in der Seite, Message Passing und wann es sich nicht lohnt.Fortgeschrittene UI & Performance
  • 16Riesige Listen: Virtual Scroll100.000 Zeilen ohne Ruckeln: CDK Virtual Scroll, itemSize, trackBy und die Alternativen (Paginierung, Infinite Scroll).Fortgeschrittene UI & Performance
  • 16Moderne Animationen & View Transitionsanimate.enter und animate.leave statt des veralteten @angular/animations, CSS-Transitions und View Transitions bei der Navigation.Fortgeschrittene UI & Performance
  • 16Memory Leaks finden und behebenSubscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.Fortgeschrittene UI & Performance
  • 17Sicherheit: XSS, Sanitizing & CSPWas Angular automatisch gegen XSS tut, wann bypassSecurityTrust gefährlich wird, dazu CSP mit Nonce, Trusted Types und XSRF.Sicherheit & Globalisierung
  • 17Authentifizierung: Tokens & RefreshEin Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.Sicherheit & Globalisierung
  • 17OAuth 2.1 & OpenID Connect mit PKCEDer Authorization-Code-Flow mit PKCE Schritt für Schritt: Verifier und Challenge, State und Nonce, das ID-Token und warum ein BFF sicherer ist.Sicherheit & Globalisierung
  • 17Internationalisierung (i18n)$localize, das i18n-Attribut, ICU plural/select, ein Build pro Sprache vs. Übersetzungen zur Laufzeit und Formatierung nach Locale.Sicherheit & Globalisierung