-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new API for react-router 6 #274
Conversation
"react-dom": ">=16.8.0", | ||
"react-dom": ">=16.8.0" | ||
}, | ||
"optionalDependencies": { | ||
"react-router-dom": ">=5.1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think react-router-dom
is actually an "optional peer dependency" (not an optional dependency)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a minimum version of react-router-dom
6.x we should specify here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left react-router-dom
in optionalDependencies
just for legacy support of react-router 5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
}
},
@@ -10,6 +10,9 @@ const makeExternalPredicate = () => { | |||
const externalArr = [ | |||
...Object.keys(pkg.peerDependencies || {}), | |||
...Object.keys(pkg.dependencies || {}), | |||
// for SecureRoute: | |||
...Object.keys(pkg.optionalDependencies || {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we export a react-router-6
bundle as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
|
||
const useHashPathForLoginCalback = config.oidc.responseMode === 'fragment' || !config.oidc.pkce; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rename this variable, use
is usually reversed for hooks
in React
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is a ref needed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes more sense to use await oktaAuth.isAuthenticated()
here, rather than the authState
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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", | ||
"react-dom": ">=16.8.0" | ||
}, | ||
"optionalDependencies": { | ||
"react-router-dom": ">=5.1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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