You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update docs and add warning for strictMatching (#8388)
This PR adds `strictMatching` runtime warning and documentation for
`@azure/msal-angular`. When `strictMatching` is not explicitly
configured on `MsalInterceptorConfiguration`, `MsalInterceptor` now
emits a one-time warning via the MSAL logger. This helps developers
discover silent 401 failures caused by misconfigured
`protectedResourceMap` keys under the v5 default strict matching
behaviour.
#### Code Changes
- **`msal.interceptor.ts`** — Inline check in the constructor emits a
logger warning when `strictMatching === undefined`, linking to the
strict matching docs.
- **`msal.interceptor.spec.ts`** — 3 new warning tests (`undefined` →
warns, `true`/`false` → no warn). Existing tests updated to pass
`strictMatching: true` to suppress the warning.
#### Documentation Changes
- **`msal-interceptor.md`** — Common failure patterns table,
environment-driven configuration guidance, troubleshooting section with
fix options, and runtime warning explanation.
- **`v4-v5-upgrade-guide.md`** — Quick checklist, v5 minor upgrade
callout, and environment-driven `protectedResourceMap` code sample with
`// TODO` migration comment.
- **`known-issues.md`** — Concise entry linking to strict matching docs.
- **`configuration.md`** — `strictMatching: false` with comments in
dynamic config samples; guidance comments in static config samples.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
"comment": "Add strictMatching runtime warning when strictMatching is not explicitly configured [#8388](https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/8388)",
Copy file name to clipboardExpand all lines: lib/msal-angular/docs/known-issues.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,11 @@
1
1
# Known issues for MSAL Angular
2
2
3
+
## 5.x
4
+
5
+
### Strict matching may silently drop `Authorization` headers
6
+
7
+
`protectedResourceMap` uses strict URL matching by default in v5, which can silently prevent the `Authorization` header from being attached (resulting in **401 Unauthorized** errors). See the [strict matching documentation](./msal-interceptor.md#strict-matching-strictmatching) for details, common failure patterns, and fix options.
8
+
3
9
## 2.0.0
4
10
* MSAL Guard's `CanLoad` does not interactively prompt for login. This will be addressed in a future release.
Copy file name to clipboardExpand all lines: lib/msal-angular/docs/msal-interceptor.md
+92-1Lines changed: 92 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -151,6 +151,8 @@ Other things to note regarding the `protectedResourceMap`:
151
151
152
152
In msal-angular v5, URL component pattern matching for`protectedResourceMap` entries uses strict matching semantics by default. The`strictMatching` field on `MsalInterceptorConfiguration` controls this behaviour.
153
153
154
+
>**⚠️ Important:** If your application sets `protectedResourceMap` keys dynamically (e.g. from environment files, `APP_INITIALIZER`, or JSON configuration) and those keys are base URLs without sub-paths or wildcards, strict matching can silently prevent the `Authorization` header from being attached, resulting in**401 errors with no build-time error and no per-request warning — only a one-time initialization warning if`strictMatching` is left unconfigured**. See [Troubleshooting strict matching](#troubleshooting-strict-matching) below.
155
+
154
156
#### What strict matching changes
155
157
156
158
| Behaviour |Legacy (`strictMatching: false`) |Strict (default in v5) |
@@ -165,6 +167,16 @@ With strict matching (the v5 default):
165
167
-A pattern like `*.contoso.com` matches `app.contoso.com` but **not**`a.b.contoso.com` (wildcard cannot span dot separators).
166
168
-A pattern like `https://graph.microsoft.com/v1.0/me` matches only that exact URL.
167
169
170
+
#### Common failure patterns
171
+
172
+
The following `protectedResourceMap` key patterns work under legacy matching but silently fail with strict matching:
173
+
174
+
| Key pattern | Outgoing request URL| Result under strict matching | Fix |
175
+
|---|---|---|---|
176
+
|`https://api.example.com`|`https://api.example.com/v1/users`| ❌ No match — key resolves to path `/`, request has path `/v1/users`|`https://api.example.com/*`|
177
+
|`https://api.example.com/`|`https://api.example.com/v1/users`| ❌ No match — trailing slash anchors the pattern to exactly `/`|`https://api.example.com/*`|
178
+
|`environment.apiConfig.uri` (e.g. `https://api.example.com`) |`https://api.example.com/v1/users`| ❌ No match — same as above |```${environment.apiConfig.uri}/*```|
179
+
168
180
#### Default behaviour inv5 (no configuration needed)
169
181
170
182
Strict matching is enabled by default. No additional configuration is required:
@@ -173,7 +185,8 @@ Strict matching is enabled by default. No additional configuration is required:
173
185
{
174
186
interactionType: InteractionType.Redirect,
175
187
protectedResourceMap: new Map([
176
-
["https://*.contoso.com/api", ["contoso.scope"]],
188
+
// Use wildcards or exact paths so strict matching works correctly
@@ -197,6 +210,84 @@ If your patterns rely on the looser matching from v4, you can set `strictMatchin
197
210
}
198
211
```
199
212
213
+
#### Guidance for environment-driven configurations
214
+
215
+
If your `protectedResourceMap` keys reference Angular `environment`values (e.g. `environment.apiConfig.uri`), check whether those values are **exact paths** (e.g. `https://graph.microsoft.com/v1.0/me`) or **bare base URLs** (e.g. `https://api.example.com`). Exact paths work correctly with strict matching and need no special handling:
216
+
217
+
```javascript
218
+
export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
219
+
const protectedResourceMap = new Map<string, Array<string>>();
220
+
// environment.apiConfig.uri is an exact path (e.g. "https://graph.microsoft.com/v1.0/me")
For truly **dynamic** configurations where the key shape is unknown at build time (e.g. `APP_INITIALIZER`, JSON loaded via `fetch`, or `platformBrowserDynamic`), set `strictMatching: false` as a temporary safe default. See [Fix options → Option B](#fix-options) below for a code example.
240
+
241
+
#### Troubleshooting strict matching
242
+
243
+
##### Symptoms
244
+
245
+
- API requests return **401 Unauthorized** after upgrading to `@azure/msal-angular` v5 (or between v5 minor versions such as 5.0.x → 5.1.x).
246
+
- The `Authorization: Bearer <token>` header is **missing** from outgoing HTTP requests.
247
+
- No build-time or runtime errors are reported — the failure is **silent**.
248
+
- The issue may only appear in certain environments (e.g. staging/production) where the API base URL differs from development.
249
+
250
+
##### Fix options
251
+
252
+
**Option A: Update keys to work with strict matching (recommended)**
253
+
254
+
Update your `protectedResourceMap` keys to use exact paths or wildcards that match under strict matching rules. This is the preferred approach because strict matching is safer and more predictable:
// strictMatching defaults to true — no need to set it
266
+
}
267
+
```
268
+
269
+
**Option B: Set `strictMatching: false` (fallback for dynamic configurations)**
270
+
271
+
If your `protectedResourceMap` keys are loaded dynamically at runtime (e.g. from `APP_INITIALIZER`, JSON config, or `platformBrowserDynamic`) and you cannot guarantee they contain exact paths or wildcards, set `strictMatching: false` as a temporary safe default:
272
+
273
+
```javascript
274
+
{
275
+
interactionType: InteractionType.Redirect,
276
+
protectedResourceMap: new Map([
277
+
[config.apiUri, config.apiScopes]
278
+
]),
279
+
// Dynamic keys may be base URLs without wildcards.
280
+
// Remove once keys are migrated to exact paths or wildcard patterns.
281
+
strictMatching: false
282
+
}
283
+
```
284
+
285
+
> **Note:** Legacy matching (`strictMatching: false`) is provided for backwards compatibility and may be removed in a future major version.
286
+
287
+
##### Runtime warning
288
+
289
+
`MsalInterceptor` emits a **one-time runtime warning** via the MSAL logger during initialization when `strictMatching` is not explicitly configured. If you see this warning, follow the fix options above.
290
+
200
291
### Optional authRequest
201
292
202
293
For more information on the optional `authRequest` that can be set in the `MsalInterceptorConfiguration`, please see our [multi-tenant doc here](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/multi-tenant.md#dynamic-auth-request).
Copy file name to clipboardExpand all lines: lib/msal-angular/docs/v4-v5-upgrade-guide.md
+29Lines changed: 29 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,35 @@ Please see the [MSAL Browser v4-v5 migration guide](https://github.com/AzureAD/m
10
10
11
11
In msal-angular v5, URL pattern matching for protectedResourceMap entries uses strict matching semantics by default. Strict matching treats pattern metacharacters as literals, anchors matches to the full URL component, and applies host wildcard rules that do not span dot separators. If your v4 configuration relied on looser matching behavior, update your protectedResourceMap patterns to align with strict matching, or set strictMatching to false to retain legacy behavior temporarily. See [MSAL Interceptor docs](./msal-interceptor.md#strict-matching-strictmatching) for more details.
12
12
13
+
> **⚠️ This change can also affect v5 minor upgrades.** If strict matching was not yet the default in the v5 minor version you originally adopted (e.g. 5.0.x), upgrading to a later v5 minor (e.g. 5.1.x) where strict matching is the default can silently break token attachment. The primary symptom is identical: **401 errors** — a runtime warning is now emitted when `strictMatching` is not explicitly configured, but the match failure itself remains silent and the `Authorization` header is no longer attached.
14
+
15
+
#### Quick checklist
16
+
17
+
1.**Review your `protectedResourceMap` keys.** Keys that are bare base URLs (e.g. `https://api.example.com`) without wildcards or sub-paths will no longer match requests to sub-paths of that URL. See [common failure patterns](./msal-interceptor.md#common-failure-patterns).
18
+
2.**Update keys to use exact paths or wildcards.** Each key should either match the exact URL your application requests, or use a `/*` wildcard suffix to match sub-paths. See [fix options](./msal-interceptor.md#fix-options).
19
+
3.**If your keys are loaded dynamically at runtime**, set `strictMatching: false` as a temporary safe default. See [guidance for environment-driven configurations](./msal-interceptor.md#guidance-for-environment-driven-configurations).
20
+
21
+
#### Environment-driven `protectedResourceMap`
22
+
23
+
If your `protectedResourceMap` keys come from Angular `environment` files, `APP_INITIALIZER`, JSON configuration, or `platformBrowserDynamic`, set `strictMatching: false` as a safe default during migration:
// TODO: Remove once protectedResourceMap keys are updated to use
34
+
// exact paths or wildcard patterns (e.g. "https://api.example.com/*").
35
+
strictMatching:false,
36
+
};
37
+
}
38
+
```
39
+
40
+
Once all keys are migrated to exact paths or wildcards, remove `strictMatching: false` (or set it to `true`) to benefit from the stricter, safer matching behaviour. See [guidance for environment-driven configurations](./msal-interceptor.md#guidance-for-environment-driven-configurations) for more details.
`[MSAL] strictMatching is enabled by default. See: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/msal-interceptor.md#strict-matching-strictmatching`,
0 commit comments