Add new API for react-router 6#274
Conversation
| "react-dom": ">=16.8.0" | ||
| }, | ||
| "optionalDependencies": { | ||
| "react-router-dom": ">=5.1.0" |
There was a problem hiding this comment.
I think react-router-dom is actually an "optional peer dependency" (not an optional dependency)
There was a problem hiding this comment.
Is there a minimum version of react-router-dom 6.x we should specify here?
There was a problem hiding this comment.
I wanted to decouple okta-react from react-router.
See my comment: #274 (comment)
What if developer wants to use @remix-run/react router, or Next.js router, reach-router?
Then he would not want a react-router to be installed in node_modules.
There was a problem hiding this comment.
I left react-router-dom in optionalDependencies just for legacy support of react-router 5
There was a problem hiding this comment.
Understood, but a optional dependencies and a peer dependencies and a optional peer dependencies are not the same thing.
Optional dependency: A dependency that is may or may not be included (optional) to use a package. In the SIW we used to use a async library called fibers to improved the compile time of sass (https://github.com/okta/okta-signin-widget/pull/2863/files)
Peer dependency: A dependency which the application and library need a common version/instance of. For example okta-react need a common instance of React (and authjs). The application consuming okta-react needs React and okta-react needs React AND it needs to be the same "instance" of React
Optional Peer Dependency: Same as a peer dependency, however including the peer dependency is optional
Optional Peer Dependencies are defined as so:
"peerDependencies": {
"@okta/okta-auth-js": "^7.x"
},
"peerDependenciesMeta": {
"@okta/okta-auth-js": {
"optional": true
}
},
| ...Object.keys(pkg.peerDependencies || {}), | ||
| ...Object.keys(pkg.dependencies || {}), | ||
| // for SecureRoute: | ||
| ...Object.keys(pkg.optionalDependencies || {}), |
There was a problem hiding this comment.
I don't think this is needed (see package.json comment)
| "types": "./dist/bundles/types/react-router-5.d.ts", | ||
| "import": "./dist/bundles/okta-react-router-5.esm.js", | ||
| "require": "./dist/bundles/okta-react-router-5.cjs.js" | ||
| } |
There was a problem hiding this comment.
Can we export a react-router-6 bundle as well?
There was a problem hiding this comment.
We could export a react-router-6 bundle with one component called like SecureOutlet that just renders <AuthRequired><Outlet /></AuthRequired>
Probably we should not name it SecureRoute as in RR5, because it's not a route.
| import LoginCallback from './LoginCallback'; | ||
| import Loading from './Loading'; | ||
|
|
||
| const useHashPathForLoginCalback = config.oidc.responseMode === 'fragment' || !config.oidc.pkce; |
There was a problem hiding this comment.
Can you rename this variable, use is usually reversed for hooks in React
There was a problem hiding this comment.
Renamed to usingFragmentForLoginCalback
| ): null => { | ||
| // We don't want any side effects (excess render, effect run) on `restoreOriginalUri` change, | ||
| // so keep and use the latest value from the ref | ||
| const restoreOriginalUriRef = React.useRef(restoreOriginalUri); |
There was a problem hiding this comment.
Why is a ref needed here?
There was a problem hiding this comment.
It's a safe way to eliminate Two custom restoreOriginalUri callbacks are detected warning issues.
When another instance of restoreOriginalUri is passed to Security, the effect would not be triggered.
Using empty dependencies array also works, but gives lint error after adding react-hooks/rules-of-hooks to ESlint config
There was a problem hiding this comment.
Yes, but that linter is used to warn to you to the possibility of a memory leak, it does not mean there is one. It's correct to pass an empty array for this case (we only want the check to fire once on component mount)
The gen3 widget does this as well:
https://github.com/okta/okta-signin-widget/blob/master/src/v3/src/components/Widget/index.tsx#L147
| export const waitForAuthenticated = ( | ||
| oktaAuth: OktaAuth | ||
| ): Promise<boolean> => { | ||
| return new Promise((resolve) => { |
There was a problem hiding this comment.
I think it makes more sense to use await oktaAuth.isAuthenticated() here, rather than the authState
There was a problem hiding this comment.
oktaAuth.isAuthenticated() can't be used for this purpose (purpose is to use support react-router's loader).
oktaAuth.isAuthenticated() will return promise that will immediately be resolved with true/false rather that actually waiting for auth state with isAuthenticated: true
(Maybe it's better to delete waitForAuthenticated util if it's confusing, and not support loader)
There was a problem hiding this comment.
oktaAuth.isAuthenticated() will return promise that will immediately be resolved with true/false rather that actually waiting for auth state with isAuthenticated: true
I'm not sure I follow this. oktaAuth.isAuthenticated will attempt to read the tokens from the tokenManager and determine their validity (and attempt a renew) before resolving
3b39c86 to
7ec4bcc
Compare
|
Closing in favour of #275 |
| "react-dom": ">=16.8.0" | ||
| }, | ||
| "optionalDependencies": { | ||
| "react-router-dom": ">=5.1.0" |
There was a problem hiding this comment.
Understood, but a optional dependencies and a peer dependencies and a optional peer dependencies are not the same thing.
Optional dependency: A dependency that is may or may not be included (optional) to use a package. In the SIW we used to use a async library called fibers to improved the compile time of sass (https://github.com/okta/okta-signin-widget/pull/2863/files)
Peer dependency: A dependency which the application and library need a common version/instance of. For example okta-react need a common instance of React (and authjs). The application consuming okta-react needs React and okta-react needs React AND it needs to be the same "instance" of React
Optional Peer Dependency: Same as a peer dependency, however including the peer dependency is optional
Optional Peer Dependencies are defined as so:
"peerDependencies": {
"@okta/okta-auth-js": "^7.x"
},
"peerDependenciesMeta": {
"@okta/okta-auth-js": {
"optional": true
}
},
|
|
||
| if (!isLoginRedirect) { | ||
| if (children) { | ||
| return (<>{children}</>); |
There was a problem hiding this comment.
We can provide samples for HashRouters, but I don't think we need direct API support. I don't think it's worth adding complexity to the API
| if (handleLoginError) { | ||
| return <ErrorReporter error={handleLoginError} />; | ||
| return <ErrorReporter error={handleLoginError} /> | ||
| } else if (!authState?.isAuthenticated) { |
There was a problem hiding this comment.
nit: can you flip this boolean, so the default case renders <Loader />
else if (authState?.isAuthentcated) {
return <ReactRouterDom.Route {....routeProps } />
}
else {
return Loading;
}
| loginError: Error | null; | ||
| } | ||
|
|
||
| const useAuthRequired = ( |
There was a problem hiding this comment.
Yes, they will be similar, but I think the implementations will different slightly
| ): null => { | ||
| // We don't want any side effects (excess render, effect run) on `restoreOriginalUri` change, | ||
| // so keep and use the latest value from the ref | ||
| const restoreOriginalUriRef = React.useRef(restoreOriginalUri); |
There was a problem hiding this comment.
Yes, but that linter is used to warn to you to the possibility of a memory leak, it does not mean there is one. It's correct to pass an empty array for this case (we only want the check to fire once on component mount)
The gen3 widget does this as well:
https://github.com/okta/okta-signin-widget/blob/master/src/v3/src/components/Widget/index.tsx#L147
| export const waitForAuthenticated = ( | ||
| oktaAuth: OktaAuth | ||
| ): Promise<boolean> => { | ||
| return new Promise((resolve) => { |
There was a problem hiding this comment.
oktaAuth.isAuthenticated() will return promise that will immediately be resolved with true/false rather that actually waiting for auth state with isAuthenticated: true
I'm not sure I follow this. oktaAuth.isAuthenticated will attempt to read the tokens from the tokenManager and determine their validity (and attempt a renew) before resolving
| } else if (!isAuthenticated) { | ||
| return Loading; | ||
| } else { | ||
| return <>{children}</>; |
There was a problem hiding this comment.
I like your idea of calling this SecureOutlet, let's forward this that
However this component should not render children and should instead return <Outlet />
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: OKTA-676780
Resolves #178
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Reviewers