Repository: authts/oidc-client-ts (ts)

Issue:
Cannot set Authorization via extraHeaders
I am trying to authenticate against a 3rd party system and that requires setting a bearer token on the /token endpoint. (seems odd to me, but I cant change it)
I tried setting this via extraHeaders unfortunately this is not working.
I have checked the code and it seems this has explicitly been blocked.
I don't suppose this can be allowed?

```
private appendExtraHeaders(
        headers: Record<string, string>,
    ): void {
        const logger = this._logger.create("appendExtraHeaders");
        const customKeys = Object.keys(this._extraHeaders);
        const protectedHeaders = [
            "authorization", // <==================================== BLOCKED!
            "accept",
            "content-type",
        ];
        if (customKeys.length === 0) {
            return;
        }
        customKeys.forEach((headerName) => {
            if (protectedHeaders.includes(headerName.toLocaleLowerCase())) {
                logger.warn("Protected header could not be overridden", headerName, protectedHeaders);
                return;
            }
            const content = (typeof this._extraHeaders[headerName] === "function") ?
                (this._extraHeaders[headerName] as ()=>string)() :
                this._extraHeaders[headerName];
            if (content && content !== "") {
                headers[headerName] = content as string;
            }
        });
    }
```

Pull request:
cannot set Authorization via extraHeaders
<!-- Please link relevant issue numbers or provide context for this change -->
Closes/fixes #1700

### Checklist

- [ ] This PR makes changes to the public API <!-- was the API report (docs/oidc-client-ts.api.md) updated by this PR? -->
- [x] I have included links for closing relevant issue numbers


Patch:
diff --git a/src/JsonService.ts b/src/JsonService.ts
index 55eaa5cc..6c83e200 100644
--- a/src/JsonService.ts
+++ b/src/JsonService.ts
@@ -91,7 +91,7 @@ export class JsonService {
             headers["Authorization"] = "Bearer " + token;
         }
 
-        this.appendExtraHeaders(headers);
+        this._appendExtraHeaders(headers);
 
         let response: Response;
         try {
@@ -147,7 +147,7 @@ export class JsonService {
             headers["Authorization"] = "Basic " + basicAuth;
         }
 
-        this.appendExtraHeaders(headers);
+        this._appendExtraHeaders(headers);
 
         let response: Response;
         try {
@@ -194,22 +194,29 @@ export class JsonService {
         return json;
     }
 
-    private appendExtraHeaders(
+    private _appendExtraHeaders(
         headers: Record<string, string>,
     ): void {
         const logger = this._logger.create("appendExtraHeaders");
         const customKeys = Object.keys(this._extraHeaders);
         const protectedHeaders = [
-            "authorization",
             "accept",
             "content-type",
         ];
+        const preventOverride = [
+            "authorization",
+        ];
         if (customKeys.length === 0) {
             return;
         }
         customKeys.forEach((headerName) => {
             if (protectedHeaders.includes(headerName.toLocaleLowerCase())) {
-                logger.warn("Protected header could not be overridden", headerName, protectedHeaders);
+                logger.warn("Protected header could not be set", headerName, protectedHeaders);
+                return;
+            }
+            if (preventOverride.includes(headerName.toLocaleLowerCase()) &&
+                Object.keys(headers).includes(headerName)) {
+                logger.warn("Header could not be overridden", headerName, preventOverride);
                 return;
             }
             const content = (typeof this._extraHeaders[headerName] === "function") ?


Test patch:
diff --git a/src/JsonService.test.ts b/src/JsonService.test.ts
index d380c1d9..a8f6d749 100644
--- a/src/JsonService.test.ts
+++ b/src/JsonService.test.ts
@@ -17,7 +17,6 @@ describe("JsonService", () => {
         "Custom-Header-1": "this-is-header-1",
         "Custom-Header-2": "this-is-header-2",
         "acCept" : "application/fake",
-        "AuthoriZation" : "not good",
         "Content-Type": "application/fail",
     };
     const dynamicExtraHeaders = {
@@ -26,7 +25,6 @@ describe("JsonService", () => {
             return "my-name-is-header-2";
         },
         "acCept" : () => "nothing",
-        "AuthoriZation" : () => "not good",
         "Content-Type": "application/fail",
     };
 
@@ -587,4 +585,86 @@ describe("JsonService", () => {
             expect(result).toEqual(json);
         });
     });
+
+    describe("_appendExtraHeaders", () => {
+        it("should add extra static headers", () => {
+            // arrange
+            const headers = {
+                "Accept": "application/json",
+            };
+            subject["_extraHeaders"] = {
+                "foo": "bar",
+            };
+
+            // act
+            subject["_appendExtraHeaders"](headers);
+
+            // assert
+            expect(headers).toMatchObject({
+                "Accept": "application/json",
+                "foo": "bar",
+            });
+        });
+
+        it("should add extra dynamic headers", () => {
+            // arrange
+            const headers = {
+                "Accept": "application/json",
+            };
+            subject["_extraHeaders"] = {
+                "foo": () => {
+                    return "bar";
+                },
+            };
+
+            // act
+            subject["_appendExtraHeaders"](headers);
+
+            // assert
+            expect(headers).toMatchObject({
+                "Accept": "application/json",
+                "foo": "bar",
+            });
+        });
+
+        it("should skip protected special headers", () => {
+            // arrange
+            const headers = {
+                "Accept": "application/json",
+            };
+            subject["_extraHeaders"] = {
+                "foo": "bar",
+                "accept": "application/xml",
+            };
+
+            // act
+            subject["_appendExtraHeaders"](headers);
+
+            // assert
+            expect(headers).toMatchObject({
+                "Accept": "application/json",
+                "foo": "bar",
+            });
+        });
+
+        it("should skip override special headers", () => {
+            // arrange
+            const headers = {
+                "Authorization": "Bearer 1",
+            };
+            subject["_extraHeaders"] = {
+                "foo": "bar",
+                "Authorization": "Bearer 2",
+            };
+
+            // act
+            subject["_appendExtraHeaders"](headers);
+
+            // assert
+            expect(headers).toMatchObject({
+                "Authorization": "Bearer 1",
+                "foo": "bar",
+            });
+        });
+    });
 });