You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular4应用中adal-angular4隐式流acquireToken首次调用报错问题

解决 Angular 4 + adal-angular4 首次调用 API 时 acquireToken 失败的问题

Hey there, I’ve run into this exact issue with adal-angular4 in Angular 4 apps using implicit flow against Azure AD APIs. Let’s break down why this happens and walk through the fixes:

Why This Happens

In implicit flow, after the first login, adal needs to asynchronously store the returned id_token and access_token in its cache. If you call acquireToken before this caching completes, you’ll get a login_required error. Subsequent calls work because the tokens are already cached by then.

Fix 1: Fix Route Guard Async Handling

Most often, the problem comes from route guards trying to fetch tokens synchronously before adal is ready. Update your guard to return an Observable and wait for the token fetch to complete:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Observable, of } from '@angular/router';
import { AdalService } from 'adal-angular4';
import { map, catchError, switchMap } from 'rxjs/operators';

@Injectable()
export class ApiAuthGuard implements CanActivate {
  constructor(private adalService: AdalService) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    const apiResource = route.data['apiResource'] as string;

    return this.adalService.acquireToken(apiResource).pipe(
      map(token => {
        // Store the token for your HTTP interceptor to use
        sessionStorage.setItem('api-access-token', token);
        return true;
      }),
      catchError(error => {
        // Handle silent login first, then fall back to interactive login if needed
        if (error.error === 'login_required') {
          return this.adalService.acquireTokenSilent(apiResource).pipe(
            map(silentToken => {
              sessionStorage.setItem('api-access-token', silentToken);
              return true;
            }),
            catchError(() => {
              this.adalService.login();
              return of(false);
            })
          );
        }
        this.adalService.login();
        return of(false);
      })
    );
  }
}

Fix 2: Pre-Fetch Tokens on App Initialization

Kick off a token fetch when your app loads to ensure the cache is populated before any API calls happen. Add this to your AppComponent:

import { Component, OnInit } from '@angular/core';
import { AdalService } from 'adal-angular4';
import { catchError } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
  private apiResource = 'https://your-azure-api-resource-url';

  constructor(private adalService: AdalService) {}

  ngOnInit(): void {
    // Try silent token acquisition first, fall back to interactive if needed
    this.adalService.acquireTokenSilent(this.apiResource).pipe(
      catchError(() => this.adalService.acquireToken(this.apiResource))
    ).subscribe(
      token => sessionStorage.setItem('api-access-token', token),
      () => this.adalService.login()
    );
  }
}

Fix 3: Add Retry Logic to Your HTTP Interceptor

If an API call fires before the token is ready, let your interceptor retry the request automatically:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AdalService } from 'adal-angular4';
import { switchMap, retry, catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private apiResource = 'https://your-azure-api-resource-url';

  constructor(private adalService: AdalService) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.adalService.acquireToken(this.apiResource).pipe(
      switchMap(token => {
        const authenticatedRequest = request.clone({
          setHeaders: {
            Authorization: `Bearer ${token}`
          }
        });
        return next.handle(authenticatedRequest);
      }),
      retry(1), // Retry once if the first call fails due to missing token
      catchError(error => {
        if (error.status === 401) {
          this.adalService.login();
          return throwError(() => new Error('Session expired - please log in again'));
        }
        return throwError(() => error);
      })
    );
  }
}

Fix 4: Verify Adal Configuration

Double-check your adal config to ensure the cache is persisted properly (localStorage is more reliable than sessionStorage for initial loads):

import { AdalConfig } from 'adal-angular4';

export const adalConfig: AdalConfig = {
  tenant: 'your-azure-tenant-id',
  clientId: 'your-app-client-id',
  redirectUri: window.location.origin + '/',
  postLogoutRedirectUri: window.location.origin + '/',
  cacheLocation: 'localStorage', // Critical for persistent token caching
  navigateToLoginRequestUrl: false
};

One last thing: Make sure your Azure AD app registration has the correct API permissions granted (and admin consent if needed), and that the resource value you’re passing to acquireToken matches the API’s audience URI exactly.

内容的提问来源于stack exchange,提问作者nesh_s

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:36:52