Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 5.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's base this PR against the dev-5.0 branch instead of master.


### Features

- [#26](https://github.com/okta/okta-react/pull/26) Added support for `react-router` 6 beta

# 4.1.0

### Other
Expand Down
55 changes: 32 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This example defines 3 routes:
// src/App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { SecureRoute, Security, LoginCallback } from '@okta/okta-react';
import { OktaAuth } from '@okta/okta-auth-js';
import Home from './Home';
Expand All @@ -137,9 +137,11 @@ class App extends Component {
return (
<Router>
<Security oktaAuth={oktaAuth}>
<Route path='/' exact={true} component={Home}/>
<SecureRoute path='/protected' component={Protected}/>
<Route path='/login/callback' component={LoginCallback} />
<Routes>
<Route path='/' element={<Home />}/>
<SecureRoute path='/protected/*' element={<Protected />}/>
<Route path='/implicit/callback' element={<LoginCallback />} />
</Routes>
</Security>
</Router>
);
Expand All @@ -166,9 +168,11 @@ const oktaAuth = new OktaAuth({
const App = () => (
<Router>
<Security oktaAuth={oktaAuth}>
<Route path='/' exact={true} component={Home}/>
<SecureRoute path='/protected' component={Protected}/>
<Route path='/login/callback' component={LoginCallback} />
<Routes>
<Route path='/' element={<Home />}/>
<SecureRoute path='/protected/*' element={<Protected />}/>
<Route path='/implicit/callback' element={<LoginCallback />} />
</Routes>
</Security>
</Router>
);
Expand Down Expand Up @@ -345,7 +349,7 @@ export default MessageList = () => {
#### Example

```jsx
import { useHistory } from 'react-router-dom';
import { useNavigate, Route, Routes, BrowserRouter as Router } from 'react-router-dom';
import { OktaAuth } from '@okta/okta-auth-js';

const oktaAuth = new OktaAuth({
Expand All @@ -355,22 +359,26 @@ const oktaAuth = new OktaAuth({
});

export default App = () => {
const history = useHistory();
const navigate = useNavigate();

const customAuthHandler = (oktaAuth) => {
// Redirect to the /login page that has a CustomLoginComponent
// This example is specific to React-Router
history.push('/login');
navigate('/login');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no change here. navigate should only be a replacement of restoreOriginalUri from oktaAuth to decouple react-router dependency in <Security>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};

return (
<Security
oktaAuth={oktaAuth}
onAuthRequired={customAuthHandler}
>
<Route path='/login' component={CustomLoginComponent}>
{/* some routes here */}
</Security>
<Router>
<Security
oktaAuth={oktaAuth}
onAuthRequired={customAuthHandler}
>
<Routes>
<Route path='/login' element={<CustomLoginComponent />}>
{/* some routes here */}
</Routes>
</Security>
</Router>
);
};
```
Expand All @@ -384,6 +392,7 @@ Assuming you have configured your application to allow the `Authorization code`

```jsx
import { OktaAuth } from '@okta/okta-auth-js';
import { Router, Route, Routes } from 'react-router-dom';

const oktaAuth = new OktaAuth({
issuer: 'https://{yourOktaDomain}.com/oauth2/default',
Expand All @@ -396,8 +405,10 @@ class App extends Component {
return (
<Router>
<Security oktaAuth={oktaAuth}>
<Route path='/' exact={true} component={Home}/>
<Route path='/login/callback' component={LoginCallback} />
<Routes>
<Route path='/' element={<Home />}/>
<Route path='/login/callback' element={<LoginCallback />} />
</Routes>
</Security>
</Router>
);
Expand All @@ -414,10 +425,8 @@ class App extends Component {

`SecureRoute` integrates with `react-router`. Other routers will need their own methods to ensure authentication using the hooks/HOC props provided by this SDK.

As with `Route` from `react-router-dom`, `<SecureRoute>` can take one of:

- a `component` prop that is passed a component
- a `render` prop that is passed a function that returns a component. This function will be passed any additional props that react-router injects (such as `history` or `match`)
As with `Route` from `react-router-dom` v6, `<SecureRoute>` can take one of:
- a `element` prop that is passed a component
- children components

### `LoginCallback`
Expand Down
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@okta/okta-react",
"version": "4.2.0",
"version": "5.0.0",
"description": "React support for Okta",
"private": true,
"scripts": {
Expand Down Expand Up @@ -43,10 +43,9 @@
},
"peerDependencies": {
"@okta/okta-auth-js": "^4.1.0",
"@types/react-router-dom": "^5.1.6",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"react-router-dom": ">=5.1.0"
"react-router-dom": "^5.1.2 || ^6.0.0-beta.0"
},
"devDependencies": {
"@babel/cli": "^7.11.6",
Expand All @@ -63,17 +62,17 @@
"@types/enzyme": "^3.10.8",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/jest": "^26.0.15",
"@types/react-router-dom": "^5.1.6",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"axios": "^0.21.0",
"babel-jest": "^26.6.3",
"chalk": "^4.1.0",
"dotenv": "^8.2.0",
"enzyme": "^3.5.1",
"enzyme-adapter-react-16": "^1.4.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"eslint": "^7.10.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jasmine": "^4.1.1",
"eslint-plugin-jest": "^24.0.2",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-node": "^11.1.0",
Expand All @@ -89,6 +88,9 @@
"polished": "^1.7.0",
"prop-types": "^15.5.10",
"protractor": "^5.4.2",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-router-dom": ">=6.0.0-beta.0",
"rimraf": "^2.6.2",
"rollup": "^2.33.1",
"rollup-plugin-cleanup": "^3.2.1",
Expand All @@ -106,4 +108,4 @@
"./",
"test/e2e/harness"
]
}
}
9 changes: 7 additions & 2 deletions src/SecureRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

import * as React from 'react';
import { useOktaAuth, OnAuthRequiredFunction } from './OktaContext';
import { Route, useRouteMatch, RouteProps } from 'react-router-dom';
import { RouteProps } from 'react-router';
import * as RR from 'react-router-dom';
const { Route } = RR;
// react-router v6 exports useMatch, react-router v5 exports useRouteMatch
const useMatch = Object.entries(RR).filter(([k, _v]) => k == 'useMatch' || k == 'useRouteMatch')[0][1];

const SecureRoute: React.FC<{
onAuthRequired?: OnAuthRequiredFunction;
Expand All @@ -21,7 +25,8 @@ const SecureRoute: React.FC<{
...routeProps
}) => {
const { oktaAuth, authState, _onAuthRequired } = useOktaAuth();
const match = useRouteMatch(routeProps);
const { path, caseSensitive } = routeProps;
const match = path ? useMatch.call(null, { path, caseSensitive }) : null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useMatch doesn't seem to be matching a route when basename property is set
we could provide useLocation().pathname value(which includes basename) as path parameter for useMatch()

const pendingLogin = React.useRef(false);

React.useEffect(() => {
Expand Down
10 changes: 5 additions & 5 deletions src/Security.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/

import * as React from 'react';
import { useHistory } from 'react-router-dom';
import { toRelativeUrl, AuthSdkError, OktaAuth } from '@okta/okta-auth-js';
import OktaContext, { OnAuthRequiredFunction } from './OktaContext';
import OktaError from './OktaError';
Expand All @@ -24,8 +23,7 @@ const Security: React.FC<{
oktaAuth,
onAuthRequired,
children
}) => {
const history = useHistory();
}) => {
const [authState, setAuthState] = React.useState(() => {
if (!oktaAuth) {
return {
Expand All @@ -46,7 +44,9 @@ const Security: React.FC<{
// Add default restoreOriginalUri callback
if (!oktaAuth.options.restoreOriginalUri) {
oktaAuth.options.restoreOriginalUri = async (_, originalUri) => {
history.replace(toRelativeUrl(originalUri, window.location.origin));
//todo: use required restoreOriginalUri prop (see PR #71)
const relativeUrl = toRelativeUrl(originalUri, window.location.origin);
window.location.href = relativeUrl;
};
}

Expand All @@ -64,7 +64,7 @@ const Security: React.FC<{
}

return () => oktaAuth.authStateManager.unsubscribe();
}, [oktaAuth, history]);
}, [oktaAuth]);

if (!oktaAuth) {
const err = new AuthSdkError('No oktaAuth instance passed to Security Component.');
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/harness/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"@types/react-dom": "^16.9.9",
"react": "^16.8.0",
"react-dom": "^16.8.0",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-router": "^6.0.0-beta.0",
"react-router-dom": "^6.0.0-beta.0",
"history": "^5.0.0",
"react-scripts": "3.4.0"
},
"devDependencies": {
Expand Down
28 changes: 14 additions & 14 deletions test/e2e/harness/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@
*/

import * as React from 'react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { Route, Routes, useNavigate } from 'react-router-dom';
import { OktaAuth } from '@okta/okta-auth-js';
import { Security, LoginCallback, SecureRoute } from '@okta/okta-react';
import Home from './Home';
import Protected from './Protected';
import CustomLogin from './CustomLogin';
import SessionTokenLogin from './SessionTokenLogin';

const App: React.FC<{
oktaAuth: OktaAuth,
customLogin: boolean
const App: React.FC<{
oktaAuth: OktaAuth;
customLogin: boolean;
}> = ({ oktaAuth, customLogin }) => {
const history = useHistory();
const navigate = useNavigate();

const onAuthRequired = async () => {
history.push('/login');
navigate('/login');
};

return (
Expand All @@ -35,14 +35,14 @@ const App: React.FC<{
oktaAuth={oktaAuth}
onAuthRequired={customLogin ? onAuthRequired : undefined}
>
<Switch>
<Route path='/login' component={CustomLogin}/>
<Route path='/sessionToken-login' component={SessionTokenLogin}/>
<SecureRoute exact path='/protected' component={Protected}/>
<Route path='/implicit/callback' component={LoginCallback} />
<Route path='/pkce/callback' component={LoginCallback} />
<Route path='/' component={Home}/>
</Switch>
<Routes>
<Route path='/login' element={<CustomLogin />}/>
<Route path='/sessionToken-login' element={<SessionTokenLogin />}/>
<SecureRoute path='/protected' element={<Protected />}/>
<Route path='/implicit/callback' element={<LoginCallback />} />
<Route path='/pkce/callback' element={<LoginCallback />} />
<Route path='/*' element={<Home />}/>
</Routes>
</Security>
<a href="/?pkce=1">PKCE Flow</a> | <a href="/">Implicit Flow</a>
</React.StrictMode>
Expand Down
Loading