I'm setting up an identity authentication for a project im currently working on. I need to be able to push a button to log into my server and then be redirected to IdentityServer4 and back again to my application.
I'm using "react-router-dom": "^4.3.1", "redux-oidc": "^3.1.4", "oidc-client": "^1.8.2",
And the projects backend is set up using .NET. I've taken the https://github.com/maxmantz/redux-oidc-example example to start my implementation and used http://docs.identityserver.io/en/aspnetcore1/quickstarts/7_javascript_client.html first to make it so that the backend and API worked.
My problem is pretty much the same as https://github.com/maxmantz/redux-oidc/issues/96 but I'm not understanding how to solve it.
I've tried solving it with different links I've found but they all keep going back to the same issue. I think thats because of the routing like mentioned earlier.
FrontEnd:
App and index:
const App = () => (
<BrowserRouter>
<Routes />
</BrowserRouter>
);
ReactDOM.render(
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<App />
</OidcProvider>
</Provider>,
document.getElementById('root')
);
Router:
const Routes = props => {
return (
<div className="App">
{console.log('Routes props, ', props)}
<Route path="/" component={Header} />
<Switch>
<Route path="/home" component={HomePage} />
<Route path="/" component={LandingPage} />
{/* I THINK MY ERROR LIES HERE, I COULD USE WHAT EVER PATH WITHOUT IT MEANING ANYTHING*/ }
<Route path="/callback" component={CallbackPage} />
</Switch>
</div>
);
};
function mapStateToProps(state) {
return {
user: state.oidc.user,
isLoadingUser: state.oidc.isLoadingUser
};
}
function mapDispatchToProps(dispatch) {
return {
dispatch
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Routes);
authConst:
import { createUserManager } from 'redux-oidc';
const userManagerConfig= {
authority: 'http://localhost:5000',
client_id: 'js',
redirect_uri: 'http://localhost:3000/callback',
response_type: 'code',
scope: 'openid profile api1',
post_logout_redirect_uri: 'http://localhost:3000'
};
const userManager = createUserManager(userManagerConfig);
export default userManager;
LoginPage:
import React from 'react';
import userManager from '../../setup/authConst';
class LoginPage extends React.Component {
onLoginButtonClick = () => {
userManager.signinRedirect();
};
render() {
return (
<div style={styles.root}>
<h3>Welcome to the redux-oidc sample app!</h3>
<p>Please log in to continue</p>
<button onClick={this.onLoginButtonClick}>Redirect Login</button>
</div>
);
}
}
export default LoginPage;
LandingPage:
import { connect } from 'react-redux';
import LoginPage from './LoginPage';
import { Redirect } from 'react-router-dom';
function LandingPage(props) {
const { user } = props;
return !user || user.expired ? (
<LoginPage />
) : (
<HomePage />
);
}
function mapStateToProps(state) {
return {
user: state.oidc.user
};
}
function mapDispatchToProps(dispatch) {
return {
dispatch
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(LandingPage);
Callback: Never touched. No console.log will be printed
import React from 'react';
import { connect } from 'react-redux';
import { CallbackComponent } from 'redux-oidc';
import { push } from 'react-router-redux';
class CallbackPage extends React.Component {
successCallback = user => {
this.props.dispatch(push('/'));
};
errorCallback = error => {
console.error(
'There was an error handling the token callback: ' + error.message
);
};
render() {
// just redirect to '/' in both cases
return (
<>
<CallbackComponent successCallback={this.successCallback}>
<div>Redirecting...</div>
</CallbackComponent>
</>
);
}
}
export default connect()(CallbackPage);
store:
import thunkMiddleware from 'redux-thunk';
//import loggerMiddleware from 'redux-logger';
import rootReducer from '../reducers/rootReducer';
import { applyMiddleware, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { loadUser } from "redux-oidc";
import userManager from './authConst'
function configureStore(preloadedState) {
const middlewares = [thunkMiddleware];
const middlewareEnhancer = applyMiddleware(...middlewares);
const enhancers = [middlewareEnhancer];
const composedEnhancers = composeWithDevTools(...enhancers);
/*if (process.env.NODE_ENV !== 'production' && module.hot) {
module.hot.accept('./reducers', () => store.replaceReducer(rootReducer))
}*/
return createStore(rootReducer, preloadedState, composedEnhancers);
}
const store = configureStore();
loadUser(store, userManager)
.then((user) => {
console.log('USER_FOUND', user);
if (user) {
store.dispatch({
type: 'redux-oidc/USER_FOUND',
payload: user,
});
}
}).catch((err) => {
console.log(err);
});
export default store;
Backend:
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "http://localhost:3000/callback" },
PostLogoutRedirectUris = { "http://localhost:3000" },
AllowedCorsOrigins = { "http://localhost:3000" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
expected to be redirected to the CallbackPage, but never gets there.
example of my URI after loginbutton: http://localhost:3000/call?code=415d7281052e165e5636cbc421b058a963c886ae73c6a8fe52ce65e1e384960e&scope=openid%20profile%20api1&state=c903848b038e4f0a83a1cb402804d868&session_state=wjishlP7ceWS0jpgWoHU9dkTKnef_BB1iSQFIh6QcJY.97b10e0098da117feb2a7a043fda362b
Just moved my Route for landing page beneath callback and it works.