maxmantz / redux-oidc Goto Github PK
View Code? Open in Web Editor NEWA package for managing OpenID Connect authentication in ReactJS / Redux apps
License: MIT License
A package for managing OpenID Connect authentication in ReactJS / Redux apps
License: MIT License
Hi there,
We like to use the triggerAuthFlow
, but we saw it was removed in v3. Can you elaborate a little bit more on why it was removed?
Is there a simple way of implementing this for ourself?
So I am using this in my app and love it. I do have a problem. When I run the dist
of the example in redux-oidc-example
the application can't seems to parse the hash/url fragment returned by google because the webserver reports a 404 on /callback and basically the callback component never gets mounted.
(i am using npms http-server
to serve the spa using your) I am getting a similar problem against another oidc provider.
It seems like I need to somehow tell my webserver that when the provider calls /callback it should pass that to the app. Do you know how this would be done in express?
basically how do i expose my apps callback? i see your prod server doesn't have anything that might give me a clue about this. TIA
I am trying out the lib and based my code on the redux-oidc-example app with Google auth.
I get the following error when returning to the callback:
redux-oidc.js:1Uncaught (in promise) Error: Error handling redirect callback: signature validation failed
I was also wondering how I could turn on logging on the oidc-client
lib to further investigate? I tried doing ìmport Oidc from 'oidc-client'; Oidc.Log.logger = console;` both in my Root React component and in my express server, but nothing shows.
Hi,
I have ejected (after no luck without) a create-react-app (1.3.1 with react-scripts (1.0.7) to try to resolve the issue. Following dependencies are added afterwards:
"dependencies": {
"babel-polyfill": "^6.23.0",
"co": "^4.6.0",
"oidc-client": "^1.3.0",
"prop-types": "^15.5.10",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.5",
"redux": "^3.6.0",
"redux-oidc": "^3.0.0-beta.7"
}
Starting index.js is updated accordingly (store is created as by ex. from react-redux, userManager is created as by ex. from redux-iodc-example; this is just to have a valid store for Provider /OidcProvider and userManager for OidcProvider):
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { OidcProvider } from 'redux-oidc';
import { createUserManager } from 'redux-oidc';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([ action.text ])
default:
return state
}
}
let store = createStore(todos, [ 'Use Redux' ]);
const userManagerConfig = {
client_id: '581912277515-8pqeloei552og7pa13iufb57iug8vu9k.apps.googleusercontent.com',
redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/callback`,
response_type: 'token id_token',
scope: 'openid profile https://www.googleapis.com/auth/youtube.readonly',
authority: 'https://accounts.google.com',
silent_redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/silent_renew.html`,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true,
};
const userManager = createUserManager(userManagerConfig);
ReactDOM.render(
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<App />
</OidcProvider>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
As you can see, I've made sure babel-polyfill is included before anything else. I did some googling and found this (old, but might be valid) comparisation/explanation between babel-polyfill and babel-runtime (which is added as devDependency by create-react-app). I also tried the setup as described on babel-runtime (with .babelrc) without luck.
I also tried explicitly adding regeneratorRuntime without luck (babel-runtime/regenerator is actually using regenerator-runtime inbehind), as following:
import regeneratorRuntime from "regenerator-runtime";
Any workaround suggestion?
Thanks!
Hey Max, hope you are well!
While working with this lib I realized I need easy access to a callback triggered when user logs in. While my previous issue provided a bit of a workaround, I was not too happy with that.
Now I found even more places that would definitely benefit from having this built-in. So my proposal.
Create a OidcComponentBase that extends React.Component.
It adds a function "userLoggedIn" passes user as a parameter.
You would place your ajax stuff that requires access token into this function.
I intend yo use react context just like in my guestbell/forms.
Therefore one context creator. OidcProvider is candidate for placing this code as it's already there and serves as a "container" if you will.
It would discourage people from inject oidc redux state where it don't belong. It would also discourage writing something like
public componentWillReceiveProps(newProps: LayoutProps) {
if (!this.props.oidc.user && newProps.oidc.user) {
// all authenticated requests go here
}
}
By extending OidcComponentBase, instead of this, you would simply write
public userLoggedIn(user: ApplicationUser) {
// all authenticated requests go here
}
And the need to inject oidc state disappears making the code easier to read and maintain.
I am more than happy to implement this (I would anyways), my question is if you would be interested in having this added to your library.
What do you think?
Hello,
I quickly checked the beta3 and I got this following error after a login process (with userManager.signinRedirect
).
An unhandled exception occurred while processing the request.
Exception: Call to Node module failed with error: Invariant Violation: React.Children.only expected to receive a single React element child.
at invariant (...\node_modules\fbjs\lib\invariant.js:44:15)
at Object.onlyChild [as only] (...\node_modules\react\lib\onlyChild.js:33:84)
at r.value (...\node_modules\redux-oidc\dist\redux-oidc.js:1:5384)
at ...\node_modules\react-dom\lib\ReactCompositeComponent.js:796:21
at measureLifeCyclePerf (...\node_modules\react-dom\lib\ReactCompositeComponent.js:75:12)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (...\node_modules\react-dom\lib\ReactCompositeComponent.js:795:25)
at ReactCompositeComponentWrapper._renderValidatedComponent (...\node_modules\react-dom\lib\ReactCompositeComponent.js:822:32)
at ReactCompositeComponentWrapper.performInitialMount (...\node_modules\react-dom\lib\ReactCompositeComponent.js:362:30)
at ReactCompositeComponentWrapper.mountComponent (...\node_modules\react-dom\lib\ReactCompositeComponent.js:258:21)
at Object.mountComponent (...\node_modules\react-dom\lib\ReactReconciler.js:46:35)
I can confirm that the beta1 is working properly but not the beta3.
I've been trying the library for a couple of days but when a I run the app I always got the message: "Uncaught Error: You must provide a user manager!" but my user manager is defined 'cause when I print the object and is not undefined nor null.
The error is triggered in the component <OidcProvider store={store} userManager={userManager}>
.
What am I doing wrong?
Both a colleague and I have tried merging your example into our app to get the Oauth token we need to make API calls using our SSO and both of us got stuck on the callback component when it tries to:
this.props.dispatch(push('/'));
... In the successCallback. I guess this is a common issue seeing as we both had it? Any help? We've been stuck on this for days!
Good day,
I'm encountered strange behaviour of OIDC middleware. I have a form (made with redux-form) which can be accessed only when user is authorised. By default I check user credentials and if there are none - I kick him to auth.server. So after getting back from callback route, my user sees his form. Everything is fine, but for some reason I get 7 "redux-oidc/LOADING_USER" events. This events are connected with my components from redux-form (also 7 of them). It doesn't break my workflow, but feels very wrong. Do you have any idea what may be wrong with it?
Hi.
This looks like an interesting library for something I am working on.
I currently have a oauth.myserver.com
which is a Identity Server 4 service. I am currently working on implementing a single sign on service on login.myserver.com
which would be a pure React application which would communicate with my oauth.myserver.com
.
Would this libray be able to aid me in this? I was thinking of letting my client application, e.g. manager.myserver.com
redirect to login.myserver.com
if the user is not logged in, then log in, and then redirect the user back to manager.myserver.com
with the token?
Hello, any suggestion/example how i can use this package with isomorfpic react application?
It seems that logout is not implemented yet.
Sorry for my stupid question, but at the moment I use the redux-oidc lib with the famous create-react-app starter kit from the React team. I integrate the app with IdentityServer4. I can log in, log out normally, but only one thing I could not make it work is silent_renew because the create-react-app doesn't allow us to add another files i.e silent_renew.html and index.js (like in the redux-oidc-example repo). My question is how can we make it work in this case?
Hi!
We are working on single sign out across browser tabs for all our clients that are using our OP. To achieve this we need to catch the UserSignedOut
event which is fired if the session check fails. It would be nice if you could dispatch an action a registering a UserSignedOut event. See oidc.client.js
Regards,
Anders
If the silent renew fails the application gets in a loop of executing USER_EXPIRED and LOADING_USER actions
I've been trying to logout from the oidc server using userManager.removeUser() but these method only reset the info stored in the client side. I've seen that in the userManager configuration it's posible to define an endsession endpoint, How can I logout from the server from the client?
I'm running into some trouble with the callback component as I am using react-router with hashHistory instead of browserHistory. If I setup the callback route with a splat like /callback/*
and use the splat part as fragment to send to userManager it works, like this: userManager.signinRedirectCallback(fragment)
.
However that is not possible with CallbackComponent as there is no way to customize the call. What I think would be needed is that here in CallbackComponent it should be possible to customize the userManager.signinRedirectCallback() call to include a fragment you extract yourself. Maybe by passing a callback into CallbackComponent.
Hi there.
First of all, how the hell this only has 71 stars? You need to popularize this a bit. I would hate see this fall into abyss without community support. It's really useful and neatly done piece of code.
Secondly and the actual issue or more of a question if you will:
My app uses automatic sign in as it's a dashboard and therefore requires user acc at all times.
I was curious what would you recommend to make this happen properly. Right now I have
if (this.props.location && this.props.location.pathname != '/callback') {
userManager.getUser().then(response => {
if (!response) {
userManager.signinRedirect();
}
});
}
Which looks a bit dodgy imho. Is there a better practice?
Secondly, is there some sort of callback that is triggered after user logs in?
I need this for some authenticated api calls. I am getting the access_token from the redux state so it would need to be populated by then.
I was trying to place that logic into previous if. But that won't get triggered this is in componentDidMount and redirect from callback will only pass in new props. Basically something that is called after redux-oidc/USER_FOUND
Hope it makes sense. Help appreciated. Cheers
We have an issue as seen below. The component's this.props.user
is null, so the userManager.signinRedirect();
is called, the store updates, the page is refreshed and thus the store loses it's value. It goes through the below check again and because this.props.user
is null again, it gets stuck in a loop.
if (!this.props.user) {
userManager.signinRedirect();
}
In your example you use:
function HomePage(props) {
const { user } = props;
return !user || user.expired ? <LoginPage/> : <MainPage />;
}
... and LoginPage then handles the signinRedirect and the app routes to MainPage. What am I doing wrong? Is it even possible to do it the way I'm doing it? How are you maintaining the store?
I am opening this issue as a result of the discussion in issue #6.
The redux-auth-wrapper package provides a higher order component to enforce authentication and authorization prior to components being loaded and the willMount and didMount methods being executed. Using this library allows for a common way to ensure a user is authenticated before accessing secure routes, and if not to redirect the user to a login page.
The benefit of using this library over a simpler check is the fact that it supports asynchronous loading of the authenticated user data. This solves the issue that was discussed in the previously mentioned issue above.
Essentially, the higher order component provided by the redux-auth-wrapper has a property, authenticatingSelector, which can be used to force it to wait until the user info is loaded using whatever asynchronous method is needed.
What is really needed to have a complete integration with that library is to be able to different between the following states:
1 - The user is not authenticated at all
2 - The user has authenticated but the authentication data has not been loaded yet (page was refreshed)
3 - The user is authenticated and the authentication data has been successfully loaded (page was not refreshed)
Right now it is impossible to tell the difference between sate 1 and state 2 so a redirect to the login page/process is always required whenever a user refreshes the page. This isn't really needed if we are able to load the user data from session storage, we just need the ability to wait for that to happen.
I am proposing, and will be opening up a PR for the following changes to allow us to differentiate between the different states:
1 - Adding a new property to the oidc state in the reducer called isLoadingUser which will default to true.
2 - On the following events, set the isLoadingUser to false, since they signify that the loading should have completed, either successfully or unsuccessfully: USER_EXPIRED, SILENT_RENEW_ERROR, USER_FOUND
With these changes, the redux-auth-wrapper package can be configured to look at the isLoadingUser state property and make the decision whether to redirect or not once that property is set to false, meaning the loaded should have completed one way or the other.
In addition to the PR the following repo provides an example of the use case:
https://github.com/jbellmore31g/redux-oidc-example
In this repo, the main route (/) is a protected route and requires the user to be logged in. If the user is has not authenticated yet they will be redirected to the /login route, which will also contain the route to redirect to after successful authentication. If the page is refresh you will notice there is no redirect to the /login route, it will simply wait for the user to be loaded and then USER_FOUND action to be dispatched. Once that has happened it will load the home component successfully.
I look forward to your thoughts on this, the tests should all be passing but will be curious if I overlooked anything. The one additional feature that is not in this PR but might be a good idea would be to have the IsLoadingUser set back to true whenever a silent renew starts. At the moment I only saw the action for whenever it fails, not for when it begins or is successful. Those would both be needed to support that use case I would think.
Thanks again!
Before the state contained the redirectUrl but now it seems to be undefined in the callback page callback. In the example the redirect seems to be always to '/'.
I've been playing with some examples (redux-oidc-examples) and I can't figure out how is that possible that the app somehow keeps state on refresh. Once I logged on I hit the refresh button and I'm still on the same page. This is really good and may help my use case tremendously once I understand how this is done. On refresh, I'd expect the store and state be destroyed and app would go back to its default state of 'please login with google'.
Hi there,
I tried to find solution for this within other issues but I couldn't. Please if it's duplicate route me to appropriate issue #.
Solution works fine locally as well as on server without HTTPS, but when I deployed this solution on test servers that require all requests to go over HTTPS I get the below pasted error when after login request comes back to callback component to load the user state.
Here is the error:
Mixed Content: The page at 'https:///callback#id_token=' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http:///.well-known/openid-configuration/jwks'. This request has been blocked; the content must be served over HTTPS.
To me it seems when callback component originates XHR request for ".well-known/openid-configuration/jwks" it sends over HTTP rather than HTTPS. I have tried to pass jwks_uri with https to user manager setting but still same issue, it's not using the url that I pass.
I'd appreciate any help.
Since updating to React v15.5 I keep getting warnings about prop-types being used from React.PropTypes. I've traced the warnings as coming from redux-oidc. Would you be able to release a v2 that fixes that?
If you can point me to a branch for v2 I can submit a PR for that myself, but I can't see one.
Following error is shown when the CallbackComponent is executing the errorCallback.
Error: No id_token in response
at t._processSigninParams (http://localhost:5004/js/bundle.js:43153:15938)
at t.validateSigninResponse (http://localhost:5004/js/bundle.js:43153:14041)
at http://localhost:5004/js/bundle.js:43153:4837
Here the structure I have in my application
Setting up the user Manager and adding middleware, added route for callback and home page
// index.js
...
import {oidc_config} from './config';
export const userManager = createUserManager(oidc_config);
const oidcMiddleware = createOidcMiddleware(userManager, () => true, false, '/callback');
...
const routes = (
<Route path='/' component={App}>
<IndexRedirect to="/home" />
....
<Route path='/callback/:authInfo' component={CallbackPage} />
</Route>
);
render(
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<Router history={hashHistory}>{routes}</Router>
</OidcProvider>
</Provider>,
document.getElementById('root')
);
Configuration for oidc
// config.js
export const oidc_config = {
authority: authorizationProvider,
client_id: client_id,
redirect_uri: 'http://localhost:5004/#/callback/',
response_type: 'id_token token',
scope: 'openid profile email api',
filterProtocolClaims: true
};
First component that is rendered and which renders LoginPage if no user exists
// HomePage.jsx
class HomePage extends Component {
render() {
const { user } = this.props;
if (!user || user.expired) {
return <LoginPage />;
} else {
this.context.router.push('/processes');
return <div></div>;
}
}
}
Login simply calls signinRedirect which goes straight to the Identitiy Server 3 login form
// LoginPage.jsx
class LoginPage extends Component {
constructor() {
super();
userManager.signinRedirect();
}
render() {
return (
<div></div>
);
}
}
Redirect from IS3 says to render this page which sets up the callbacks for the CallbackComponent. successCallback is never called because of the above mentioned error, but errorCallback is executed. I extracted the token from the location hash and set it in my application.
// CallbackPage.jsx
class CallbackPage extends Component {
constructor(props, context) {
super(props, context);
this.successCallback = (user) => {
//const urlBeforeRedirection = user.state.redirectUrl;
//this.context.router.push(urlBeforeRedirection);
};
this.errorCallback = (error) => {
const regex = /&access_token=(.*?)&token_type=/;
this.props.setToken(this.props.params.authInfo.match(regex)[1], this.context.router);
};
}
render() {
return (
<CallbackComponent
successCallback={this.successCallback}
errorCallback={this.errorCallback} />
);
}
}
Action sets the token in the app and routes to a specific page, application works after that and can be used, but not as intended
// actions.js for login
export function setToken(token, router) {
return function(dispatch) {
dispatch(setLoginToken(token));
router.push('/processes');
};
}
The request to the server looks like this
Request URL:https://ouridentityserver/core/connect/authorize?client_id=theclientid&redirect_uri=http://localhost:5004/callback/&response_type=id_token%20token&scope=openid%20profile%20email%20api&state=alargevalue&nonce=anotherlargevalue
Request Method:GET
Status Code:302 Found
Remote Address:1.2.3.4:443
The response from the server looks like this
HTTP/1.1 302 Found
Content-Length: 0
Location: http://localhost:5004/#/callback/id_token=largeIdTokenHere&access_token=largeAccessTokenHere&token_type=Bearer&expires_in=3600&scope=openid%20profile%20email%20api&state=6e36fc965faf481ca11f0ee71f2008db&session_state=largervaluehere
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Wed, 04 Jan 2017 09:04:25 GMT
Well, as you can see I have the problem that the successCallback is never called because there is no id_token in the response from the IS3. But instead I get the location from it with the necessary tokens.
My colleague says that the IS3 is configured correctly and he set up an example that used oidc-client-js, which works and a user object exists.
What do you think, is that a problem with the IS3 setup, or is something else working wrong here. How do your responses look like from the Identity Server?
Hello,
I have a react application with Server Side Rendering.
I used the custom InMemoryWebStorage mentionned in a earlier closed GitHub Issues.
import { createUserManager } from 'redux-oidc';
import InMemoryStorageStore, { UserManager, WebStorageStateStore } from 'oidc-client';
// create a user manager instance
const config = {
...
userStore: new WebStorageStateStore({ store: InMemoryStorageStore })
}
const userManager : UserManager = createUserManager(config);
export default userManager;
But I have this following exception:
Call to Node module failed with error: Prerendering failed because of error: ReferenceError: localStorage is not defined
at Function.get (D:\Dev\iNUI\Store\airxtouch\node_modules\oidc-client\lib\oidc-client.min.js:1:12917)
What do I missed? How can I solve this?
Thanks.
We're using react's server-side rendering feature. We tried to use redux-oidc in our application, unfortunately it looks like redux-oidc does not work on the server, because it requires sessionStorage
, which is not available in node. Is there a way to make it work with SSR?
Here's a stack trace FWIW:
[1] [piping] can't execute file: /path/to/project/bin/server.js
[1] [piping] error given was: ReferenceError: sessionStorage is not defined
[1] at Function.n.get (/path/to/project/node_modules/redux-oidc/dist/redux-oidc.js:3:14695)
[1] at new e (/path/to/project/node_modules/redux-oidc/dist/redux-oidc.js:12:28204)
[1] at new e (/path/to/project/node_modules/redux-oidc/dist/redux-oidc.js:12:20743)
[1] at Object.n [as createUserManager] (/path/to/project/node_modules/redux-oidc/dist/redux-oidc.js:1:1578)
[1] at Object.<anonymous> (/path/to/project/src/utils/oauth/molManager.js:15:21)
[1] at Module._compile (module.js:413:34)
[1] at normalLoader (/path/to/project/node_modules/babel-core/lib/api/register/node.js:199:5)
[1] at Object.require.extensions.(anonymous function) [as .js] (/path/to/project/node_modules/babel-core/lib/api/register/node.js:216:7)
[1] at Module.load (module.js:357:32)
[1] at Module._load (module.js:314:12)
I upgraded redux-oidc to v3.0. I followed the example app for making the changes. After moving to 3.0, the promises returned by redux-thunk are undefined.
return function (dispatch) {
dispatch({ type: 'PUBNUB_CONNECTING' });
return connect(authenticationToken)
.then(() => {
dispatch({ type: 'PUBNUB_CONNECTED', payload: user });
}).catch(error => {
dispatch({ type: 'PUBNUB_DISCONNECTED', payload: { error } });
const reconnect = () => connectpn(authenticationToken)(dispatch);
setTimeout(reconnect, 1500);
});
};
With redux-oidc v2, the promise from redux-thunk dispatch was returning correctly. With redux-oidc v3, the promise is returned as undefined after dispatching through the thunk middleware.
Looks like the newest version of oidc-client-js (1.3.0) broke something. Locking it to 1.2.2 resolved the issue. @maxmantz
In my app, I'm trying to show a fatal error message when the OAuth server is down. I can't seem to find a way to do this. The middleware logs the error in the console, but I can't seem to catch it. Maybe consider adding an error property to the state or dispatch an error action of some kind?
I would think that the user property being null and isLoadingUser being false would mean that something has gone wrong, but there are brief moments when that state exists but nothing is wrong.
Maybe isLoadingUser should initially be true and only go to false once the user has been found or an error has occurred? Then user == null && isLoadingUser == false
would mean that something is wrong.
Am I totally off base here? Do I need to just write my own method to ping the OAuth server and make sure it's accessible?
Great work on the project! The only issue I'm having is that all my thrown errors seem to get caught by the middleware and presented (incorrectly) as oidc middleware errors. I think the issue is coming from this line:
redux-oidc/src/oidcMiddleware.js
Line 50 in b8f7f7b
What do you think? Is there a way to have my own code's exceptions bubble to the top without getting caught?
Hi,
I'm using React Router 4 and AFIAK there is no version of react-router-redux that works well with RR4. Can redux-oidc be used without react-router-redux? I have got the user signin redirect working but will the middleware that is injected by redux-oidc work? I presume not?
I'm using redux-oidc based on the usage example you provided. It is working fine in IE and Firefox. However, when I use it in Chrome:
I have tried both ^3.0.0-beta.3 and ^3.0.0-beta.7 and also tried both older and newer versions of react, redux etc.
In the console I see the following when I get de-authenticated:
Action type: redux-oidc/USER_EXPIRING
store.js:14 Action payload: undefined
store.js:15 State before: Object {routing: Object, oidc: Object}
store.js:17 State after: Object {routing: Object, oidc: Object}
store.js:13 Action type: redux-oidc/SILENT_RENEW_ERROR
store.js:14 Action payload: Error: Frame window timed out
at t._error (oidc-client.min.js:74)
at t._timeout (oidc-client.min.js:74)
Thanks
Hi, I'm getting this error everytime I try to use redux-oidc. I've added it to the entry in the webpack.config.js and also imported it in the entry to my app. Any idea?
This package is built to support react-native. Due to my lack of experience with react-native I'm opening this issue to summarize the findings by users of this library.
Hi,
This is my scenario:
With triggerAuthFlow set to true a user has expired or is not logged in at all. The middleware sets a key in local storage oidc.expired: true. The user is then redirected to the log in page, at this point the user decides they don't want to log in right now and closes their browser.
Later that day, perhaps. The user tries to go back to the application. They are not logged in, but the middleware bypasses the log in process because the first if statement in this code evaluates to false. So my app is stuck (as far as the user is concerned) in an irrecoverable state.
// the middleware
return (store) => (next) => (action) => {
if (shouldValidate(store.getState(), action) && !localStorage.getItem(STORAGE_KEY)) {
// IF: validation should occur...
if (!storedUser || storedUser.expired) {
// IF: user hasn't been found or is expired...
localStorage.setItem(STORAGE_KEY, true);
userManager.getUser()
.then((user) => getUserSuccessCallback(next, userManager, user, triggerAuthFlow, action))
.catch(getUserErrorCallback);
} else {
// ELSE: user has been found and NOT is expired...
return next(action);
}
} else {
// ELSE: validation should NOT occur...
return next(action);
}
}
I'm not sure how I can detect and prevent this scenario. I understand why oidc.expired is set to true (so that when you come back to the Callback route, it doesn't look them back to authentication.
This library is working great for me otherwise. Thanks!
Is it somehow possible to remove the user object from redux state if a silent renew fails?
Users tend to refresh their browser, which clears the redux store. As I understand it, the user data is still in the localStorage. Couldn't the middleware look in localStorage, challenge the OpenID Provider with the found data, and on success populate the store again without the user having to actively do a login cycle?
I noticed that each login cycle stores an entry in localStorage. Is this by design, and why is that? Couldn't the localStore just hold the last successful login entry?
Thank you for the library, excited about getting it up and running :)
In the example given, BrowserHistory is used, which assumes some server side configuration. I need to use HashHistory, however this method does not work and I get a blank page with the callback and id_token etc in the hash URL. Please advise on what I need to do differently when using react routers HashHistory.
Hi,
I'm mentally stuck how to tackle my problem properly. I use redux-oidc to authorize myself, user is set up by the library and I can do my API calls with the user token in the state, like this:
// API requests - done with redux-thunk
export function fetchData() {
return function(dispatch, getState) {
const token = getState().oidc.user.access_token;
if (token === '') {
return;
}
dispatch(requestData());
const request = new Request(fetchDataUrl, {
method: 'GET',
headers: getAuthHeader(token)
});
return fetch(request)
.then(response => response.json())
.then(json => {
if (json.StatusCode !== 200) {
triggerNotification(json.StatusCode, json.ResponseMessage);
}
return json;
})
.then(json => dispatch(receiveData(json)))
.catch(() => {
triggerNotification(900);
});
};
}
The problem is, when the user reloads the page, there is no user in the state, because the middleware is not yet finished with adding the user to it.
Using it like this in a component:
class Data extends Component {
componentWillMount() {
this.props.fetchData().then(() => {
this.props.sortData(this.props.sort.column, this.props.sort.direction);
});
}
....
I don't know how to tackle that problem. I was thinking about the userManger.getUser().then() promise, but I wasn't able to make it work yet. Any ideas what to pay attention to?
Is there a hook in the library to only do the fetchData when the user is loaded into the state?
I hope it's ok if I ask that here.
There's possibility of doing a silent "refresh" of the token before the current token expires by issuing in hidden "iframe" (or similar) a request to identity server with "&prompt=none" in query string. If the token is still valid identity server will "refresh" the token.
Is this feature already implemented in redux-oidc?
Can I request the redux-oidc/dist/redux-oidc.js file to use
define(["react"]
instead of
define(["React"]
This is to remove the warnings like:
WARNING in ./~/react/lib/getNodeForCharacterOffset.js
There is another module with an equal name when case is ignored.
I was thinking, a lot can go wrong in the redirect road. States not matching, or even an exception. As for now, an error is thrown. How can I as a user of the library decide what to display to the user in different error scenarios? Right now it logs to console and is plain stuck on the "Redirecting..." view.
Could a solution be to pass in an errorCallback
as a property to the CallbackComponent
to make it more flexible?
I have my web application on domain1.com and my auth server on domain2.com (and my api on domain3.com). When I try the silent renew functionality I get...
Refused to display 'http://domain2.com/authorizations/new?client_id=...' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
How does anyone get the iframe silent renew technique to work if most browsers (eg. Chrome in this case) disallow going across origins (I have tried setting 'X-Frame-Options' to something more liberal but Chrome doesn't support this)?
Thanks again for this super useful library!
I have integrated my app to work with React-Redux-Oidc. However, one issue I am having is that when I have a user who is logged in and I refresh the page the state.oidc.user is null again. Thus, my app thinks the user is logged out even though I still see the OIDC metadata in session storage.
When I ran your example application locally I see that you did not have this issue. But I am unable to figure out what mechanism on the example app is keeping state.oidc.user persistent on page refreshes?
Hi,
When using the oidcMiddleware in Version 3 (beta) it prevents dispatch from returning anything.
In our case we needed to get a Promise from the action but after implementing oidcMiddleware we only received undefined.
Lets say having following action:
function fetchAsync() {
return function (getState, dispatch) {
return fetch....
}
}
using dispatch(fetchAsync()).then() will result in an error as the result from dispatch will be undefined.
This is fixed when changing:
https://github.com/maxmantz/redux-oidc/blob/master/src/oidcMiddleware.js#L46
to
// the middleware
return (store) => (next) => (action) => {
return co(middlewareHandler(next, action, userManager));
}
I'm however not sure if that will fix non Promise return types cause of "co" returning a promise instead.
Hello! Thanks for the package!!
I didn't find the answer in the documentation so I wonder why do we need to have a second HTML file for the Silent renew feature.
I have React application with a single HTML file and registered route for the silent renewal (routing is done using react-router). With this setup I'm able to perform a token renewal at least one time.
For some reason the second time, when application renews a token, I get SILENT_RENEW_ERROR with message saying Frame window timed out. I wonder if this issue is related with having only one HTML file.
Thank you!
Update I've changed the accessTokenExpiringNotificationTime and set it to 58 minutes (having a token with 1 hour expiration interval). After this change my application successfully renews token every 2 minutes without any timeout errors. So, I guess, the question about Frame window timed out should be asked in oidc-client-js repo issue tracker.
Could you then answer my first question about the need of having separate HTML file for silent renewal. Is anything wrong with having a single file? Thank you again!
just a quick question, I need something exactly like this package, but I want to use it with Angular2, how hard would it be to use this in my Angular2 project?
I noticed some deps to react. I guess my real question is:
Will you ever separate this package from react?
Hi @maxmantz - again, great library! I am having a problem with the 2.2.1 version of your library, which is probably just my lack of knowledge.
When an API returns me a 401 I want to handle this by performing an explicit silent renew as per this comment IdentityModel/oidc-client-js#298 (comment)
Note: I have auto silent renew working perfectly - it redirects to login page when silent renew fails if you have logged out from the OP server (due to SILENT_RENEW_ERROR being handled by redux-oidc I presume). In my silent_renew.jsx file I simply import the userManager and call userManager.signinSilentCallback();
However, the explicit silent renew is not going so well. When I receive the 401 in javascript (and I am logged out of the OP server) I call userManager.signinSilent()
but from looking at redux tools it doesn't dispatch a SILENT_RENEW_ERROR.
I tried this as an experiment...
let theUserManager = userManager;
userManager.signinSilent().then(user => {
// This doesn't seem to make any difference when I am logged into the OP Server
theUserManager.signinSilentCallback();
}, err => {
// This seems to cause the SILENT_RENEW_ERROR to be dispatched
theUserManager.events._raiseSilentRenewError(err);
});
I'm not sure if I should have to do this manual wiring up? Even when I do I find that the reducer at https://github.com/maxmantz/redux-oidc/blob/v2.2.1/src/reducer/reducer.js#L20 isn't clearing out the user in the redux state. I'm just speculating, but I wonder if the problem is that the userManager instance is different from the instance created and hence somehow wouldn't have a reducer listening to the SILENT_RENEW_ERROR. I've been tearing my hair out trying to solve this. If you've any advice I'd greatly appreciate it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.