react-oidc-context
react-oidc-context copied to clipboard
Callback url causes 404 page to be displayed
In the documentation, it is stated
You still need to setup a redirect uri, which must point to your application, but you do not need to create that route.
I found this misleading because in the common case of using react-router-dom@6 with a 404 catch-all route, the 404 page is displayed when the code exchange callback route is navigated to.
Should we not encourage the user to set up a route like so?
<Route path={ROUTES.CALLBACK} element={<LoadingIndicator />} />
Good point, was not aware of that react-router-dom@6 feature. The route you show above is probably too limiting for everybody. Maybe it enough to extend the sentence:
You still need to setup a redirect uri, which must point to your application, but you do not need to create that route.
You still need to setup a redirect uri, which must point to your application. Unless you have not setup a 404 catch-all route
behavior, you do not need to create that route.
@pamapa yes, I agree my example is too specific for the docs. What you said sound good, except I think it should read "Unless you have set up a ...".
To anyone coming up on this issue, a quick tip: make sure to do a browser history replace and not push when you advance from the callback URL, otherwise your history will move back to it unexpectedly.
Can someone please point me to some documentation for this? For example, do I not need protected routes with this? Is the suggestion to use useAuth in each component that requires you to be logged in and it'll just work? I'm currently using the react-oidc library, but it's not being maintained and the documentation is poor so I am thinking of switching to this.
If I have a component that makes api calls, and if the user has had the page open all night and comes back to click on a button to fetch some data, will I get a 401 due to inactivity? Or is it supposed to continuously get new access tokens? I'm just wondering what options I have and if I can get some visibility into what's happening even on a high level.
Why am I getting "Oops... no matching state found in storage" after clicking login (using the example in the readme)? I can't find that text anywhere in the source.
I'm trying to contrast this with oidc-react. That library has you create the UserManager class and pass it to the context. What does this one do that oidc-react doesn't? Or vice versa.
Thanks
This library creates the UserManager inside. At the end there is not much code in this library you, best is you read it directly. A keep part of this library can be seen here: If auth parameters are detected it acts accordingly.
- In order to check if the user has logged in or not you need to use
auth.isAuthenticated. - When calling an api which needs the access token, you need to inject that access token in your fetch. As documented here
@pamapa thanks for the reply. One thing I'm having trouble with is I have a hook that creates an instance of axios with some interceptors to add the access token to each request-and handles a couple of error scenarios (401 and 403).
What's happening is when you've been sitting idle for a while and you come back to a page and click on a component that initiates a request, the server returns with a 401. In the interceptor's error function, I'm saying if there's a 401 call auth.signIn. But the ui component that initiates the request is getting the error from the hook while the auth.singIn() is occurring. The user sees a toast error for a second or two and then it goes away and you're logged in. Here's the hook and example code so you can see the logic:
// the hook all components use:
export function useCreateAxiosInstance() {
const auth = useAuth();
const instance = axios.create();
instance.interceptors.request.use(function (config) {
// this is similiar to auth.isAuthenticated in the new library (I think):
if (auth && auth.userData) {
config.headers = { "Authorization": `Bearer ${auth.userData!!.access_token}` }
}
return config;
});
instance.interceptors.response.use(function (response) {
return response;
}, function (error) {
if (error.response.status === 401) {
auth.signIn(); // sign them in again after token expired
}
else if (error.response.status === 403) {
window.location.assign(window.location.origin + "/not-authorized");
}
return Promise.reject(error);
});
return instance;
}
// components use the hook like this to get their data:
import useCreateAxiosInstance from '../axiosstuff';
import {getCustomer} from '/cust/api';
function someComponent() {
const {axiosInstance} = useCreateAxiosInstance();
useEffect(() => {
async function getData() {
try {
const data = await getCustomerInfo(custId, axiosInstance); // inject instance
setCustomer(data) // standard state stuff
}
catch(error) {
displayToast('error occurred');
}
getData();
}, [])
}
// In customer.ts file:
export async function getCustomerInfo(custId: string, axiosInstance: AxiosInstance) {
const response = await axiosInstance.get(`${URL}${custId}`);
return response.data as Customer;
}
It was my understanding that it's supposed to silently renew the access token before expiring so the 401 is unexpected. But if this behavior is normal, how do I avoid showing the error in this specific case (ie, how to differentiate between a 401 when someone is just idle and a 401 for a different reason- such as maybe the user has been revoked, etc). Should I just have some retry logic to give it time to finish the auth.signIn? Or should I change my approach here? Thanks!
Note- this is with the react-oidc library on which this new library is based. I haven't switched over to this one yet. Same principal should apply whether I'm using the old one or this one, I would think.
I do not know in which application context you use your hook function useCreateAxiosInstance, maybe its result is cached inside the function someComponent and does not recalculate what you think it should. Maybe adding some logging in your code might help. Also notice that the underlying library oidc-client-ts has full logging support, see the documentation of it. With the logs enabled you can ensure that you receive a new access token...
The silent renew process is implemented in the underlying library oidc-client-ts, enabled by default but can be disabled...
With this trick you can artificially reduce the silent renew timer, to renew every 30 seconds:
settings.accessTokenExpiringNotificationTimeInSeconds = YOUR_ACCESS_TOKEN_EXPIRE_TIME - 30,
Something else: it might be better to decouple getting the access token via useAuth in useCreateAxiosInstance. You simply get it from session/localStorage, as documented in the README.md.
This is the lib the auth context is coming from: https://github.com/bjerkio/oidc-react It returns this:
export interface AuthContextProps {
signIn: (args?: unknown) => Promise<void>;
signInPopup: () => Promise<void>;
signOut: () => Promise<void>;
signOutRedirect: (args?: unknown) => Promise<void>;
userManager: UserManager;
userData?: User | null;
isLoading: boolean;
}
It's based on the oidc-client.js (the predecessor to oidc-client-ts). I think what might be happening in my scenario is auth.userData is gone (but why I don't know) so it never adds the token to the request, which would cause a 401. Then the error is caught in the interceptor and it does the auth.signIn().
I could decouple the useAuth from the hook, but then every component would need to know about access tokens.
Maybe I should just switch to this one as it seems to have more support and its api exposes more. I just need to sell it to my boss. Where is an example of how to enable logging? I went here and I don't see it: https://www.npmjs.com/package/react-oidc-context#documentation
Can you show an example, because you're right- I really do need logging to know what's really going on.
You can enable the logging of oidc-client-ts. See here https://authts.github.io/oidc-client-ts/#logging
I'm getting this 404 issue as well. It works fine on localhost but once I publish the app and the user authenticates, it redirects me to a 404 page.
I'm relatively inexperienced so I'm having a bit of trouble understanding how you fixed it?
I have updated and triple checked the authorised redirect URLs, I don't have a catch all for 404 errors, I'm using react-dom-router v6, and I have the route:
<Route path="/linkedin" element={ <LinkedInCallback /> } />.
Any help you could give me would be great - I've been at this for a bunch of hours and I'm running out of ideas.