Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When cloning request headers in HttpInterceptor, assertValidHeaders expects string, number, or array, but the headers are a Map #59189

Open
Entroper opened this issue Dec 13, 2024 · 0 comments

Comments

@Entroper
Copy link

Which @angular/* package(s) are the source of the bug?

common

Is this a regression?

No

Description

I'm using an HttpInterceptor to set the authorization header on requests to our API. When we try to set the header, the interceptor throws from assertValidHeaders.

See this comment for what I agree may be causing the problem: #49353 (comment)

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

Unexpected value of the `normalizedNames` header provided. Expecting either a string, a number or an array, but got: `[object Map]`.

The headers object is:

{
  "normalizedNames": {},
  "lazyUpdate": [
    {
      "name": "Authorization",
      "value": "Bearer <token>",
      "op": "s"
    }
  ],
  "headers": {},
  "lazyInit": {
    "normalizedNames": {},
    "lazyUpdate": null
  }
}

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 18.2.8
Node: 18.20.4
Package Manager: npm 10.7.0
OS: linux x64

Angular: 18.2.8
... animations, cli, common, compiler, compiler-cli, core, forms
... google-maps, localize, platform-browser
... platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1802.8
@angular-devkit/build-angular   18.2.8
@angular-devkit/core            18.2.8
@angular-devkit/schematics      18.2.8
@schematics/angular             18.2.8
rxjs                            7.5.7
typescript                      5.5.4
zone.js                         0.14.10

Anything else?

The interceptor:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
	constructor(private authService: AuthenticationService) { }

	intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
		return from(this.handle(req, next));
	}

	private async handle(req: HttpRequest<any>, next: HttpHandler): Promise<HttpEvent<any>> {
		if (req.url.startsWith(environment.webApiUrl) || req.url.startsWith(environment.adminApiUrl)) {
			// Make sure we're authenticated for API calls.  These promises will already be complete if we are.
			if (!(await this.authService.isAuthenticated())) {
				await this.authService.login();
			}

			// We're now logged in, if we possibly can be.
			const accessToken = await this.authService.token();
			if (accessToken) {
				const cloned = req.clone({
					headers: req.headers.set('Authorization', accessToken)
				});

				console.log(req.headers);
				console.log(cloned.headers);
				return await lastValueFrom(next.handle(cloned));
			}
		}

		// We'll fall back to here if we couldn't get logged in, and try the request anyway.
		return await lastValueFrom(next.handle(req));
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant