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 (
+
+ );
+};
+
+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"