Skip to content

Commit 3de4325

Browse files
jo-arroyokonstantin-msftCopilot
authored
[v5] Add React 18 support (#8437)
## Add React 18 support to `@azure/msal-react` Widens peer dependency support from React 19-only to React 18 and 19. No runtime code changes were required. ### Changes **`lib/msal-react`** - `peerDependencies.react`: `"^19.2.1"` → `"^18.0.0 || ^19.0.0"` - Updated `README.md`, `getting-started.md`, and `migration-guide-v4-v5.md` to document dual React version support **Samples** - Widened `react`/`react-dom` ranges to `"^18.0.0 || ^19.2.1"` in `react-router-sample`, `typescript-sample`, and `b2c-sample` - Widened `@types/react`/`@types/react-dom` to `"^18.0.0 || ^19.1.3"` in `typescript-sample` **CI** - Added `.pipelines/templates/msal-react-react18-e2e.yml`: local 3P-only template that overrides React to `^18` via `npm pkg set overrides` and runs E2E tests against the three non-Next.js samples (`nextjs-sample` requires React 19) - Wired into `.pipelines/3p-e2e.yml` alongside the existing React 19 jobs --------- Co-authored-by: Konstantin <kshabelko@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 352d1d5 commit 3de4325

12 files changed

Lines changed: 280 additions & 40 deletions

File tree

.pipelines/3p-e2e.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,16 @@ extends:
119119
- "b2c-sample"
120120
debug: ${{ parameters.debug }}
121121
npmInstallTimeout: ${{ parameters.npmInstallTimeout }}
122+
- template: .pipelines/templates/msal-react-react18-e2e.yml@self
123+
parameters:
124+
poolType: ${{ parameters.poolType }}
125+
sourceBranch: ${{ variables.sourceBranch }}
126+
debug: ${{ parameters.debug }}
127+
npmInstallTimeout: ${{ parameters.npmInstallTimeout }}
128+
samples:
129+
- "react-router-sample"
130+
- "typescript-sample"
131+
- "b2c-sample"
122132
- ${{ if eq(parameters.runAngularTests, true) }}:
123133
- template: .pipelines/templates/e2e-tests.yml@1P
124134
parameters:
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
parameters:
2+
- name: "poolType"
3+
type: string
4+
default: "linux"
5+
values:
6+
- "linux"
7+
- "windows"
8+
- name: "sourceBranch"
9+
type: string
10+
- name: "npmInstallTimeout"
11+
type: number
12+
default: 15
13+
- name: "debug"
14+
type: boolean
15+
default: false
16+
- name: "samples"
17+
type: object
18+
default:
19+
- "react-router-sample"
20+
- "typescript-sample"
21+
- "b2c-sample"
22+
23+
jobs:
24+
- ${{ each sample in parameters.samples }}:
25+
- job: validate_msal_react_r18_${{ replace(sample, '-', '_') }}
26+
displayName: "[msal-react] - ${{ sample }} - React 18 - Node v22"
27+
28+
pool:
29+
type: ${{ parameters.poolType }}
30+
isCustom: true
31+
name: "Azure Pipelines"
32+
${{ if eq(parameters.poolType, 'linux') }}:
33+
vmImage: "ubuntu-latest"
34+
${{ elseif eq(parameters.poolType, 'windows') }}:
35+
vmImage: "windows-latest"
36+
37+
variables:
38+
- template: .pipelines/templates/variables.yml@1P
39+
- name: "npm_config_cache"
40+
value: "$(Pipeline.Workspace)/.npm"
41+
- name: "samplePath"
42+
${{ if eq(parameters.poolType, 'windows') }}:
43+
value: "samples/msal-react-samples/${{ sample }}"
44+
${{ else }}:
45+
value: "samples/msal-react-samples/${{ sample }}"
46+
47+
steps:
48+
- template: .pipelines/templates/build-var-dump.yml@1P
49+
parameters:
50+
debug: ${{ parameters.debug }}
51+
52+
- checkout: self
53+
54+
- task: CmdLine@2
55+
displayName: "Checkout ${{ variables.sourceBranch }} branch"
56+
inputs:
57+
script: git switch $(sourceBranch) || git switch -c $(sourceBranch) origin/$(sourceBranch) || git switch -c $(sourceBranch) origin/dev
58+
59+
- template: .pipelines/templates/node-install-wrapper.yml@1P
60+
parameters:
61+
nodeVersion: "22"
62+
63+
- task: npmAuthenticate@0
64+
displayName: "Authenticate to npm package registry"
65+
inputs:
66+
workingFile: ./.npmrc
67+
68+
- template: .pipelines/templates/npm-install.yml@1P
69+
parameters:
70+
clean: true
71+
name: "msal-react"
72+
workspace: "samples/msal-react-samples/${{ sample }}"
73+
workingDir: "./"
74+
useInternalFeed: false
75+
timeout: ${{ parameters.npmInstallTimeout }}
76+
77+
- task: CmdLine@2
78+
displayName: "Override sample to React 18 via npm overrides"
79+
inputs:
80+
targetType: inline
81+
script: |
82+
npm pkg set "overrides.react=^18" "overrides.react-dom=^18" "overrides.@types/react=^18" "overrides.@types/react-dom=^18"
83+
npm install
84+
workingDirectory: "./"
85+
86+
- ${{ if eq(parameters.poolType, 'linux') }}:
87+
- template: .pipelines/templates/npm-install.yml@1P
88+
parameters:
89+
name: "rollup linux platform deps"
90+
workingDir: "./"
91+
paramList: "--no-save"
92+
packageList: "@rollup/rollup-linux-x64-gnu"
93+
useInternalFeed: false
94+
timeout: ${{ parameters.npmInstallTimeout }}
95+
96+
- task: Npm@1
97+
displayName: "Build msal-react"
98+
inputs:
99+
command: "custom"
100+
customCommand: "run build:all"
101+
workingDir: "lib/msal-react"
102+
103+
- task: Npm@1
104+
displayName: "Build msal-node"
105+
inputs:
106+
command: "custom"
107+
customCommand: "run build:all"
108+
workingDir: "lib/msal-node"
109+
110+
- task: Npm@1
111+
displayName: "Build ${{ sample }}"
112+
inputs:
113+
command: "custom"
114+
customCommand: "run build"
115+
workingDir: "$(samplePath)"
116+
117+
- task: Npm@1
118+
displayName: "Generate certificates"
119+
inputs:
120+
command: "custom"
121+
customCommand: "run generate:certs --if-present"
122+
workingDir: "$(samplePath)"
123+
124+
- template: .pipelines/templates/install-keyvault-secrets.yml@1P
125+
parameters:
126+
keyVaultName: "msidlabs"
127+
secretsFilter: "LabVaultAccessCert"
128+
secretName: "LabVaultAccessCert"
129+
pfxPath: "$(Build.SourcesDirectory)/LabCert.pfx"
130+
pemPath: "$(Build.SourcesDirectory)/LabCert.pem"
131+
132+
- task: CmdLine@2
133+
displayName: "Create screenshot folder"
134+
inputs:
135+
script: mkdir -p ${{ replace(variables.samplePath, '/', '\') }}\test\screenshots\react18
136+
137+
- task: Npm@1
138+
displayName: "Test ${{ sample }}"
139+
timeoutInMinutes: 30
140+
retryCountOnTaskFailure: 3
141+
inputs:
142+
command: "custom"
143+
customCommand: "run test:e2e -- --sample=${{ sample }} --detectOpenHandles --forceExit --reporters=default --reporters=jest-junit"
144+
workingDir: "$(samplePath)"
145+
env:
146+
AZURE_CLIENT_CERTIFICATE_PATH: $(Build.SourcesDirectory)/LabCert.pem
147+
AZURE_CLIENT_ID: $(AZURE_CLIENT_ID)
148+
AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: "true"
149+
AZURE_TENANT_ID: $(AZURE_TENANT_ID)
150+
JEST_JUNIT_OUTPUT_NAME: "${{ sample }}.xml"
151+
SESSION_SECRET: $(EXPRESS_SESSION_SECRET)
152+
153+
- task: PublishTestResults@2
154+
displayName: "Publish Test Results"
155+
condition: succeededOrFailed()
156+
inputs:
157+
testResultsFiles: "$(samplePath)/${{ sample }}.xml"
158+
testRunTitle: "${{ sample }}-react18"
159+
160+
- task: CopyFiles@2
161+
condition: failed()
162+
inputs:
163+
SourceFolder: "${{ variables.samplePath }}/test/screenshots/react18"
164+
Contents: "**"
165+
TargetFolder: $(Build.ArtifactStagingDirectory)
166+
167+
- task: PublishPipelineArtifact@1
168+
displayName: "Upload screenshots to artifacts"
169+
condition: succeededOrFailed()
170+
inputs:
171+
targetPath: $(Build.ArtifactStagingDirectory)
172+
artifact: "drop_e2e_test_validate_msal_react_r18_${{ replace(sample, '-', '_') }}"
173+
publishLocation: "pipeline"
174+
175+
- template: .pipelines/templates/remove-keyvault-secrets.yml@1P
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Add React 18 support for MSAL React [#8437](https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/8437)",
4+
"packageName": "@azure/msal-react",
5+
"email": "joarroyo@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

lib/msal-react/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
## Supported Environments
44

55
- msal-react supports all modern mainstream browsers (Chrome, Firefox, Safari, Edge)
6-
- msal-react supports React versions 19+
6+
- msal-react supports React versions 18 and 19
77

88
Never use or suggest APIs or features that are not supported by the environments listed above.

lib/msal-react/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ The `@azure/msal-react` package described by the code in this folder uses the [`
4040

4141
| MSAL React version | MSAL support status | Supported React versions |
4242
| --------------------- | ------------------- | ------------------------ |
43-
| MSAL React v5 | Active development | 19 |
43+
| MSAL React v5 | Active development | 18, 19 |
4444
| MSAL React v3 | In maintenance | 16, 17, 18, 19 |
4545
| MSAL React v1, v2 | In maintenance | 16, 17, 18 |
4646

lib/msal-react/docs/getting-started.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
`@azure/msal-react` is built on the [React context API](https://reactjs.org/docs/context.html) and all parts of your app that require authentication must be wrapped in the `MsalProvider` component. You will first need to [initialize](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/initialization.md) an instance of `PublicClientApplication` then pass this to `MsalProvider` as a prop.
1212

13+
> **React version support:** `@azure/msal-react` v5 supports both React 18 and React 19. Choose the rendering API that matches your React version.
14+
1315
```javascript
1416
import React from "react";
15-
import ReactDOM from "react-dom";
17+
import { createRoot } from "react-dom/client";
1618

1719
import { MsalProvider } from "@azure/msal-react";
1820
import { Configuration, PublicClientApplication } from "@azure/msal-browser";
@@ -35,7 +37,9 @@ const AppProvider = () => (
3537
</MsalProvider>
3638
);
3739

38-
ReactDOM.render(<AppProvider />, document.getElementById("root"));
40+
// React 18+ rendering
41+
const root = createRoot(document.getElementById("root"));
42+
root.render(<AppProvider />);
3943
```
4044

4145
All components underneath `MsalProvider` will have access to the `PublicClientApplication` instance via context as well as all hooks and components provided by `@azure/msal-react`.

lib/msal-react/docs/migration-guide-v4-v5.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,26 @@ MSAL Browser v5 requires a dedicated redirect page/bridge for authentication flo
1515

1616
Please see the [COOP section in the MSAL Browser v4-v5 migration guide](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/v4-migration.md#cross-origin-opener-policy-coop-support).
1717

18-
## Dropped support for old React versions
19-
MSAL React v5 supports React 19.2.1 or greater. It no longer supports React 16, 17, or 18.
18+
## Updated React version support
19+
MSAL React v5 supports React 18.0.0 or greater and React 19.2.1 or greater. It no longer supports React 16 or 17.
2020

21-
## React 18 compatibility note
21+
## Peer dependency ranges
2222

23-
React 18 has reached end of life, which is why MSAL React v5 dropped support for it.
23+
MSAL React v5 declares its `react` peer dependency as `"^18.0.0 || ^19.2.1"`. This means:
2424

25-
If your app is still on React 18, installing `@azure/msal-react@^5` may fail due to peer dependency constraints.
25+
- Applications using React 18.x will satisfy the peer dependency without errors or warnings.
26+
- Applications using React 19.2.1 or newer (within the React 19.x line) will satisfy the peer dependency without errors or warnings.
27+
- No `--legacy-peer-deps` flag is required for either version.
2628

27-
- Temporary install workaround: `npm install --legacy-peer-deps`
28-
- This may allow installation and basic flows may continue to work in some apps, but React 18 is not supported or validated for v5
29-
- You may see untested behavior around rendering/lifecycle timing, StrictMode interactions, or future patch updates
29+
### Known considerations
3030

31-
For production workloads, upgrade React to 19.2.1 or greater before moving to `@azure/msal-react@^5`.
31+
- **`@types/react`**: If you use TypeScript, install the `@types/react` version matching your React major version (`@types/react@^18` for React 18, `@types/react@^19` for React 19). Both are compatible with the MSAL React v5 public API surface.
32+
- **`@testing-library/react`**: v14+ supports React 18; v16+ supports both React 18 and 19. Choose the version that matches your React version.
33+
- **`react-dom`**: Install the same major version of `react-dom` as `react` (e.g., `react-dom@^18` with `react@^18`).
3234

3335
## Migrating from Create React App (react-scripts)
3436

35-
Create React App is deprecated and `react-scripts` does not support React 19. If your app uses `react-scripts`, you **must** migrate to a different build tool before upgrading to `@azure/msal-react@^5`.
37+
Create React App is deprecated and `react-scripts` does not support React 19. If your app uses `react-scripts`, you should migrate to a different build tool before upgrading to `@azure/msal-react@^5`. While React 18 is supported by `@azure/msal-react@^5`, CRA is no longer maintained and Vite is recommended.
3638

3739
**Recommended: Migrate to [Vite](https://vite.dev/)**
3840

@@ -86,9 +88,13 @@ Create React App is deprecated and `react-scripts` does not support React 19. If
8688
8789
7. Remove CRA-specific environment variables (`SKIP_PREFLIGHT_CHECK`, `DISABLE_ESLINT_PLUGIN`) from `.env` files.
8890
89-
8. Upgrade React and install MSAL:
91+
8. Upgrade React (if needed) and install MSAL:
9092
```bash
93+
# React 19 (recommended)
9194
npm install react@^19.2.1 react-dom@^19.2.1
95+
# OR React 18 (also supported)
96+
npm install react@^18.0.0 react-dom@^18.0.0
97+
# Then install MSAL
9298
npm install @azure/msal-browser@^5 @azure/msal-react@^5
9399
```
94100

lib/msal-react/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
},
5858
"peerDependencies": {
5959
"@azure/msal-browser": "^5.5.0",
60-
"react": "^19.2.1"
60+
"react": "^18.0.0 || ^19.2.1"
6161
},
6262
"devDependencies": {
6363
"@azure/msal-browser": "^5.5.0",
@@ -83,4 +83,4 @@
8383
"tslib": "^2.0.0",
8484
"typescript": "^4.9.5"
8585
}
86-
}
86+
}

0 commit comments

Comments
 (0)