diff --git a/CHANGELOG.md b/CHANGELOG.md index fd10c6fe..d6b9c801 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 6.6.0 + +- [#239](https://github.com/okta/okta-react/pull/239) + - Fixes `Two custom restoreOriginalUri callbacks are detected` warning, will only fire once on `` didMount + - Fixes react-router v6 routing samples, no longer calls `/authorize` on page load with valid, active session + # 6.5.0 ### Others diff --git a/samples/routing/react-router-dom-v5-hash/src/App.tsx b/samples/routing/react-router-dom-v5-hash/src/App.tsx index f2f89e98..024cc985 100644 --- a/samples/routing/react-router-dom-v5-hash/src/App.tsx +++ b/samples/routing/react-router-dom-v5-hash/src/App.tsx @@ -24,7 +24,7 @@ import Routes from './components/Routes'; const oktaAuth = new OktaAuth({ issuer: process.env.ISSUER, clientId: process.env.SPA_CLIENT_ID, - redirectUri: window.location.origin + '/login/callback' + redirectUri: window.location.origin + '/' }); function App() { diff --git a/samples/routing/react-router-dom-v6-hash/src/App.tsx b/samples/routing/react-router-dom-v6-hash/src/App.tsx index cce4a1fb..c0dfba09 100644 --- a/samples/routing/react-router-dom-v6-hash/src/App.tsx +++ b/samples/routing/react-router-dom-v6-hash/src/App.tsx @@ -24,7 +24,7 @@ import Routes from './components/Routes'; const oktaAuth = new OktaAuth({ issuer: process.env.ISSUER, clientId: process.env.SPA_CLIENT_ID, - redirectUri: window.location.origin + '/login/callback' + redirectUri: window.location.origin + '/' }); function App() { diff --git a/samples/routing/react-router-dom-v6-hash/src/components/SecureRoute.tsx b/samples/routing/react-router-dom-v6-hash/src/components/SecureRoute.tsx index b1b0ebee..c6869100 100644 --- a/samples/routing/react-router-dom-v6-hash/src/components/SecureRoute.tsx +++ b/samples/routing/react-router-dom-v6-hash/src/components/SecureRoute.tsx @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useOktaAuth } from '@okta/okta-react'; import { toRelativeUrl } from '@okta/okta-auth-js'; import { Outlet } from 'react-router-dom'; @@ -20,15 +20,19 @@ import Loading from './Loading'; export const RequiredAuth: React.FC = () => { const { oktaAuth, authState } = useOktaAuth(); - if (oktaAuth.token.isLoginRedirect()) { - return (); - } + useEffect(() => { + if (!authState) { + return; + } - if (!authState || !authState?.isAuthenticated) { - const originalUri = toRelativeUrl(window.location.href, window.location.origin); - oktaAuth.setOriginalUri(originalUri); - oktaAuth.signInWithRedirect(); + if (!authState?.isAuthenticated) { + const originalUri = toRelativeUrl(window.location.href, window.location.origin); + oktaAuth.setOriginalUri(originalUri); + oktaAuth.signInWithRedirect(); + } + }, [oktaAuth, !!authState, authState?.isAuthenticated]); + if (!authState || !authState?.isAuthenticated) { return (); } diff --git a/samples/routing/react-router-dom-v6/src/components/SecureRoute.tsx b/samples/routing/react-router-dom-v6/src/components/SecureRoute.tsx index 11539237..f8f7669c 100644 --- a/samples/routing/react-router-dom-v6/src/components/SecureRoute.tsx +++ b/samples/routing/react-router-dom-v6/src/components/SecureRoute.tsx @@ -10,7 +10,7 @@ * See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useOktaAuth } from '@okta/okta-react'; import { toRelativeUrl } from '@okta/okta-auth-js'; import { Outlet } from 'react-router-dom'; @@ -19,11 +19,19 @@ import Loading from './Loading'; export const RequiredAuth: React.FC = () => { const { oktaAuth, authState } = useOktaAuth(); - if (!authState || !authState?.isAuthenticated) { - const originalUri = toRelativeUrl(window.location.href, window.location.origin); - oktaAuth.setOriginalUri(originalUri); - oktaAuth.signInWithRedirect(); + useEffect(() => { + if (!authState) { + return; + } + + if (!authState?.isAuthenticated) { + const originalUri = toRelativeUrl(window.location.href, window.location.origin); + oktaAuth.setOriginalUri(originalUri); + oktaAuth.signInWithRedirect(); + } + }, [oktaAuth, !!authState, authState?.isAuthenticated]); + if (!authState || !authState?.isAuthenticated) { return (); } diff --git a/src/Security.tsx b/src/Security.tsx index 5b568d32..56861029 100644 --- a/src/Security.tsx +++ b/src/Security.tsx @@ -55,7 +55,7 @@ const Security: React.FC<{ restoreOriginalUri(oktaAuth as OktaAuth, originalUri); }) as ((oktaAuth: OktaAuth, originalUri?: string) => Promise); - }, [oktaAuth, restoreOriginalUri]); + }, []); // empty array, only check on component mount React.useEffect(() => { if (!oktaAuth) { diff --git a/test/apps/v6-app/.gitignore b/test/apps/v6-app/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/test/apps/v6-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/test/apps/v6-app/index.html b/test/apps/v6-app/index.html new file mode 100644 index 00000000..13267ed5 --- /dev/null +++ b/test/apps/v6-app/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/test/apps/v6-app/package.json b/test/apps/v6-app/package.json new file mode 100644 index 00000000..3dccc24d --- /dev/null +++ b/test/apps/v6-app/package.json @@ -0,0 +1,26 @@ +{ + "name": "@okta/test.app.v6-app", + "private": true, + "version": "0.0.0", + "scripts": { + "prestart": "vite build", + "start": "vite preview --port 8080", + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-router-dom": "6.3.0", + "@okta/okta-auth-js": "*", + "@okta/okta-react": "*" + }, + "devDependencies": { + "@types/react": "^17.0.33", + "@types/react-dom": "^17.0.10", + "@vitejs/plugin-react": "^1.3.2", + "typescript": "^4.5.4", + "vite": "^2.8.0" + } +} \ No newline at end of file diff --git a/test/apps/v6-app/src/App.css b/test/apps/v6-app/src/App.css new file mode 100644 index 00000000..15adfdc7 --- /dev/null +++ b/test/apps/v6-app/src/App.css @@ -0,0 +1,24 @@ +.App { + text-align: center; +} + +.App-logo { + animation: App-logo-spin infinite 20s linear; + height: 80px; +} + +.App-header { + background-color: #222; + height: 150px; + padding: 20px; + color: white; +} + +.App-intro { + font-size: large; +} + +@keyframes App-logo-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} diff --git a/test/apps/v6-app/src/App.tsx b/test/apps/v6-app/src/App.tsx new file mode 100644 index 00000000..e15585bf --- /dev/null +++ b/test/apps/v6-app/src/App.tsx @@ -0,0 +1,70 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import * as React from 'react'; +import { Route, Routes, useNavigate } from 'react-router-dom'; +import { OktaAuth, toRelativeUrl } from '@okta/okta-auth-js'; +import { Security, LoginCallback } from '@okta/okta-react'; +import { SecureRoute } from './SecureRoute'; +import Home from './Home'; +import Protected from './Protected'; +import CustomLogin from './CustomLogin'; +import WidgetLogin from './WidgetLogin'; +import SessionTokenLogin from './SessionTokenLogin'; + +const App: React.FC<{ + oktaAuth: OktaAuth; + customLogin: boolean; + baseUrl: string; +}> = ({ oktaAuth, customLogin, baseUrl }) => { + const navigate = useNavigate(); + + const onAuthRequired = async () => { + navigate('/login'); + }; + + const onAuthResume = async () => { + navigate('/widget-login'); + }; + + const restoreOriginalUri = async (_oktaAuth: OktaAuth, originalUri: string) => { + navigate(toRelativeUrl(originalUri || '/', window.location.origin)); + }; + + return ( + + + + } /> + } /> + } /> + }> + } /> + + } /> + Loading...

} + />}/> + } /> +
+
+ PKCE Flow | Implicit Flow +
+ ); +}; + +export default App; diff --git a/test/apps/v6-app/src/CustomLogin.tsx b/test/apps/v6-app/src/CustomLogin.tsx new file mode 100644 index 00000000..663ac276 --- /dev/null +++ b/test/apps/v6-app/src/CustomLogin.tsx @@ -0,0 +1,26 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import * as React from 'react'; +import { useOktaAuth } from '@okta/okta-react'; + +const CustomLogin: React.FC = () => { + const { oktaAuth } = useOktaAuth(); + + React.useEffect(() => { + oktaAuth.signInWithRedirect(); + }, [oktaAuth]); + + return null; +}; + +export default CustomLogin; diff --git a/test/apps/v6-app/src/Home.tsx b/test/apps/v6-app/src/Home.tsx new file mode 100644 index 00000000..1b8aa5fc --- /dev/null +++ b/test/apps/v6-app/src/Home.tsx @@ -0,0 +1,58 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +// implement with "useOktaAuth" hook +import * as React from 'react'; +import { Link } from 'react-router-dom'; +import { useOktaAuth } from '@okta/okta-react'; + +const Home: React.FC = () => { + const { oktaAuth, authState } = useOktaAuth(); + const [renewMessage, setRenewMessage] = React.useState(''); + + const login = async () => oktaAuth.signInWithRedirect({ originalUri: '/protected' }); + const logout = async () => oktaAuth.signOut(); + const renewToken = (tokenName: string) => async () => { + oktaAuth.tokenManager.renew(tokenName) + .then(() => setRenewMessage(`Token ${tokenName} was renewed`)) + .catch(e => setRenewMessage(`Error renewing ${tokenName}: ${e}`)); + } + + if (!authState) { + return null; + } + + const button = authState.isAuthenticated ? + : + ; + + const pkce = oktaAuth.isPKCE(); + + return ( +
+
{ pkce ? 'PKCE' : 'implicit'}
+
+ Home
+ Protected
+ Session Token Login
+ Widget Login
+ {button} + { authState.isAuthenticated ? : null } + { authState.isAuthenticated ? : null } +
+ { renewMessage } +
+
+ ); +}; + +export default Home; diff --git a/test/apps/v6-app/src/Protected.tsx b/test/apps/v6-app/src/Protected.tsx new file mode 100644 index 00000000..98738c8a --- /dev/null +++ b/test/apps/v6-app/src/Protected.tsx @@ -0,0 +1,42 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +// implement with "withOktaAuth" HOC +import * as React from 'react'; +import { OktaAuth } from '@okta/okta-auth-js'; +import { withOktaAuth } from '@okta/okta-react'; + +const Protected: React.FC<{ oktaAuth: OktaAuth }> = ({ oktaAuth }) => { + const [userInfo, setUserInfo] = React.useState(''); + + React.useEffect(() => { + const fetchUser = async () => { + const claims = await oktaAuth.getUser(); + const userinfo = JSON.stringify(claims, null, 4); + setUserInfo(userinfo); + }; + + fetchUser(); + }, [oktaAuth]); + + const logout = async () => oktaAuth.signOut(); + + return ( +
+
Protected!
+ {userInfo &&
 {userInfo} 
} + +
+ ); +}; + +export default withOktaAuth(Protected); diff --git a/test/apps/v6-app/src/SecureRoute.tsx b/test/apps/v6-app/src/SecureRoute.tsx new file mode 100644 index 00000000..e50be655 --- /dev/null +++ b/test/apps/v6-app/src/SecureRoute.tsx @@ -0,0 +1,39 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import React, { useEffect } from 'react'; +import { useOktaAuth } from '@okta/okta-react'; +import { toRelativeUrl } from '@okta/okta-auth-js'; +import { Outlet } from 'react-router-dom'; + + +export const SecureRoute: React.FC = () => { + const { oktaAuth, authState } = useOktaAuth(); + + useEffect(() => { + if (!authState) { + return; + } + + if (!authState?.isAuthenticated) { + const originalUri = toRelativeUrl(window.location.href, window.location.origin); + oktaAuth.setOriginalUri(originalUri); + oktaAuth.signInWithRedirect(); + } + }, [oktaAuth, !!authState, authState?.isAuthenticated]); + + if (!authState || !authState?.isAuthenticated) { + return (

Loading...

); + } + + return (); +} diff --git a/test/apps/v6-app/src/SessionTokenLogin.tsx b/test/apps/v6-app/src/SessionTokenLogin.tsx new file mode 100644 index 00000000..fa7ed1f3 --- /dev/null +++ b/test/apps/v6-app/src/SessionTokenLogin.tsx @@ -0,0 +1,58 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import * as React from 'react'; +import { AuthTransaction } from '@okta/okta-auth-js'; +import { useOktaAuth } from '@okta/okta-react'; + +const SessionTokenLogin: React.FC = () => { + const { oktaAuth } = useOktaAuth(); + const [sessionToken, setSessionToken] = React.useState(undefined); + const [username, setUsername] = React.useState(''); + const [password, setPassword] = React.useState(''); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + oktaAuth.signInWithCredentials({ + username, + password + }) + .then((res: AuthTransaction) => { + setSessionToken(res.sessionToken); + oktaAuth.token.getWithRedirect({sessionToken: res.sessionToken}); + }) + .catch((err: Error) => { + console.log('Found an error', err); + }); + }; + const handleUsernameChange = (e: React.ChangeEvent) => setUsername(e.target.value); + const handlePasswordChange = (e: React.ChangeEvent) => setPassword(e.target.value); + + if (sessionToken) { + return null; + } + + return ( +
+ + +
+ ); +}; + +export default SessionTokenLogin; diff --git a/test/apps/v6-app/src/WidgetLogin.tsx b/test/apps/v6-app/src/WidgetLogin.tsx new file mode 100644 index 00000000..6ac17afc --- /dev/null +++ b/test/apps/v6-app/src/WidgetLogin.tsx @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ +import * as React from 'react'; +import { useOktaAuth } from '@okta/okta-react'; + +declare global { + // TODO: Remove "any"s once widget has TS definitions + interface Window { OktaSignIn: any } // eslint-disable-line @typescript-eslint/no-explicit-any +} + +const WidgetLogin: React.FC<{ + baseUrl: string; +}> = (baseUrl) => { + const { oktaAuth } = useOktaAuth(); + const widgetRef = React.useRef(null); + + React.useEffect( () => { + if (!widgetRef.current) { + return; + } + + const widget = new window.OktaSignIn({ + baseUrl, + authClient: oktaAuth, // Note: the interactionCodeFlow below requires PKCE enabled on the authClient + useInteractionCodeFlow: true, // Set to true, if your org is OIE enabled + }); + + widget.on('afterError', (context: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any + console.log({ context }); + // The Widget is ready for user input + }); + + widget.renderEl( + { el: widgetRef.current }, + (res: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any + console.log(res); + oktaAuth.handleLoginRedirect(res.tokens); + }, + (err: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any + console.log({ err }); + throw err; + }, + ); + + return () => widget.remove(); + }, [oktaAuth, baseUrl]); + + return ( +
+

Note: Requires interaction code flow and PKCE

+
+
+ ); +}; +export default WidgetLogin; diff --git a/test/apps/v6-app/src/index.css b/test/apps/v6-app/src/index.css new file mode 100644 index 00000000..b4cc7250 --- /dev/null +++ b/test/apps/v6-app/src/index.css @@ -0,0 +1,5 @@ +body { + margin: 0; + padding: 0; + font-family: sans-serif; +} diff --git a/test/apps/v6-app/src/index.tsx b/test/apps/v6-app/src/index.tsx new file mode 100644 index 00000000..f15e81e0 --- /dev/null +++ b/test/apps/v6-app/src/index.tsx @@ -0,0 +1,43 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { OktaAuth } from '@okta/okta-auth-js'; +import './index.css'; +import App from './App'; +import { BrowserRouter as Router } from 'react-router-dom'; + +const { ISSUER, CLIENT_ID } = process.env; + +// To perform end-to-end PKCE flow we must be configured on both ends: when the login is initiated, and on the callback +// The login page is loaded with a query param. This will select a unique callback url +// On the callback load we detect PKCE by inspecting the pathname +const url = new URL(window.location.href); +const pkce = !!url.searchParams.get('pkce') || url.pathname.indexOf('pkce/callback') >= 0; +const redirectUri = window.location.origin + (pkce ? '/pkce/callback' : '/implicit/callback'); +const customLogin = !!url.searchParams.get('customLogin'); +const baseUrl = ISSUER?.split('/oauth2')[0] || 'ISSUER-NOT-SUPPLIED'; + +const oktaAuth = new OktaAuth({ + issuer: ISSUER, + clientId: CLIENT_ID, + redirectUri, + pkce +}); + +ReactDOM.render( + + + + , document.getElementById('root') +); diff --git a/test/apps/v6-app/src/logo.svg b/test/apps/v6-app/src/logo.svg new file mode 100644 index 00000000..6b60c104 --- /dev/null +++ b/test/apps/v6-app/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/apps/v6-app/src/react-app-env.d.ts b/test/apps/v6-app/src/react-app-env.d.ts new file mode 100644 index 00000000..e37d0a97 --- /dev/null +++ b/test/apps/v6-app/src/react-app-env.d.ts @@ -0,0 +1,13 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +/// diff --git a/test/apps/v6-app/src/vite-env.d.ts b/test/apps/v6-app/src/vite-env.d.ts new file mode 100644 index 00000000..669c7407 --- /dev/null +++ b/test/apps/v6-app/src/vite-env.d.ts @@ -0,0 +1,13 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +/// diff --git a/test/apps/v6-app/tsconfig.json b/test/apps/v6-app/tsconfig.json new file mode 100644 index 00000000..c8bdc640 --- /dev/null +++ b/test/apps/v6-app/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/test/apps/v6-app/tsconfig.node.json b/test/apps/v6-app/tsconfig.node.json new file mode 100644 index 00000000..e993792c --- /dev/null +++ b/test/apps/v6-app/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] +} diff --git a/test/apps/v6-app/vite.config.js b/test/apps/v6-app/vite.config.js new file mode 100644 index 00000000..6f9c67c4 --- /dev/null +++ b/test/apps/v6-app/vite.config.js @@ -0,0 +1,64 @@ +/*! + * Copyright (c) 2017-Present, Okta, Inc. and/or its affiliates. All rights reserved. + * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") + * + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and limitations under the License. + */ + +// "IMPORTANT: THIS FILE IS GENERATED, CHANGES SHOULD BE MADE WITHIN '@okta/generator'" + +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path'; +import oktaEnv from '@okta/env'; + +oktaEnv.setEnvironmentVarsFromTestEnv(__dirname); + +process.env.CLIENT_ID = process.env.SPA_CLIENT_ID || process.env.CLIENT_ID; +process.env.OKTA_TESTING_DISABLEHTTPSCHECK = process.env.OKTA_TESTING_DISABLEHTTPSCHECK || false; +process.env.USE_INTERACTION_CODE = process.env.USE_INTERACTION_CODE || false; + +const env = {}; + +// List of environment variables made available to the app +[ + 'ISSUER', + 'CLIENT_ID', + 'OKTA_TESTING_DISABLEHTTPSCHECK', + 'USE_INTERACTION_CODE', +].forEach((key) => { + if (!process.env[key]) { + throw new Error(`Environment variable ${key} must be set. See README.md`); + } + env[key] = process.env[key]; +}); + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + define: { + 'process.env': env + }, + resolve: { + alias: { + 'react-router-dom': path.resolve(__dirname, 'node_modules/react-router-dom') + } + }, + server: { + port: 8080 + }, + build: { + rollupOptions: { + // always throw with build warnings + onwarn (warning, warn) { + warn('\nBuild warning happened, customize "onwarn" callback in vite.config.js to handle this error.'); + throw new Error(warning); + } + } + } +}) diff --git a/test/jest/security.test.tsx b/test/jest/security.test.tsx index 1a91cd51..a916113a 100644 --- a/test/jest/security.test.tsx +++ b/test/jest/security.test.tsx @@ -394,4 +394,22 @@ describe('', () => { expect(wrapper.find(Security).html()).toBe('

AuthSdkError: No restoreOriginalUri callback passed to Security Component.

'); }); }); + + it('should only log warning of restoreOriginalUri option once', () => { + oktaAuth.options = { + restoreOriginalUri + }; + const mockProps = { + oktaAuth, + restoreOriginalUri + }; + const warning = 'Two custom restoreOriginalUri callbacks are detected. The one from the OktaAuth configuration will be overridden by the provided restoreOriginalUri prop from the Security component.'; + const spy = jest.spyOn(console, 'warn'); + const wrapper = mount(); + expect(spy).toBeCalledTimes(1); + expect(spy).toBeCalledWith(warning); + spy.mockClear(); + wrapper.setProps({restoreOriginalUri: 'foo'}); // forces rerender + expect(spy).toBeCalledTimes(0); + }); }); diff --git a/yarn.lock b/yarn.lock index 796192a3..b1206948 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8624,6 +8624,14 @@ react-router-dom@6.2.1: history "^5.2.0" react-router "6.2.1" +react-router-dom@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d" + integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw== + dependencies: + history "^5.2.0" + react-router "6.3.0" + react-router@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" @@ -8663,6 +8671,13 @@ react-router@6.2.1: dependencies: history "^5.2.0" +react-router@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" + integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== + dependencies: + history "^5.2.0" + react-test-renderer@^16.0.0-0: version "16.14.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae"