Reputation: 15237
I am trying to get ReactJS working with IdentityServer4 via oidc-client-js
library.
PROBLEM
I click the login button and I get redirected to IdentityServer4, once I login, I get redirect to /login-callback
and then from there I get redirected to /
but I get the following error in the console:
I am not sure what I'm doing wrong, but I've tried all sorts and nothing seems to work.
CODE
All code is open-source and sits here.
App.jsx
// other code ommited, but this is a route
<AuthHandshake path="/login-callback" />
AuthHandshake.jsx
import React from "react";
import { AuthConsumer } from "../AuthProvider/AuthProvider";
function AuthHandshake() {
return <AuthConsumer>{value => value.loginCallback()}</AuthConsumer>;
}
export default AuthHandshake;
AuthProvider.jsx
import React, { useState } from "react";
import { navigate } from "@reach/router";
import { UserManager, WebStorageStateStore } from "oidc-client";
import AuthContext from "../../contexts/AuthContext";
import { IDENTITY_CONFIG } from "../../utils/authConfig";
IDENTITY_CONFIG.userStore = new WebStorageStateStore({
store: window.localStorage
});
const userManager = new UserManager(IDENTITY_CONFIG);
const login = () => {
console.log("Login button click handled.");
userManager.signinRedirect();
};
const logout = () => {
userManager.signoutRedirect();
};
export function AuthProvider(props) {
const [user, setUser] = useState(null);
const loginCallback = () => {
userManager.signinRedirectCallback().then(
user => {
window.history.replaceState(
{},
window.document.title,
window.location.origin
);
setUser(user);
navigate("/");
},
error => {
console.error(error);
}
);
};
const providerValue = {
login: login,
logout: logout,
loginCallback: loginCallback,
isAuthenticated: user
};
const Provider = () => {
if (user) {
return (
<AuthContext.Provider value={providerValue}>
{props.children}
</AuthContext.Provider>
);
} else {
return <div className="auth-provider">{props.children}</div>;
}
};
return (
<>
<AuthContext.Provider value={providerValue}>
{props.children}
</AuthContext.Provider>
</>
);
}
export const AuthConsumer = AuthContext.Consumer;
On the IdentityServer side, I have set the post logout redirect to the same thing /login-callback
new Client
{
ClientId = "bejebeje-react-local",
ClientName = "Bejebeje ReactJS SPA Client",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
RequireClientSecret = false,
RequireConsent = false,
RedirectUris = { "http://localhost:1234/login-callback" },
PostLogoutRedirectUris = { "http://localhost:1234/logout-callback" },
AllowedCorsOrigins = { "http://localhost:1234" },
AllowedScopes = { "openid", "profile", "bejebeje-api-local" },
AllowOfflineAccess = true,
RefreshTokenUsage = TokenUsage.ReUse,
}
Where am I going wrong?
Upvotes: 2
Views: 5570
Reputation: 4714
I had to add response_mode: 'query'
to the UserManager
.
var mgr = new Oidc.UserManager({ response_mode: 'query' });
mgr.signinRedirectCallback().then(res => {
window.location = "/signin-callback";
}).catch(error => {
window.location = "/";
})
Upvotes: 2
Reputation: 799
Try this here.. https://github.com/JwanKhalaf/Bejebeje.React/blob/bug/fix-no-code-response-on-redirect/src/components/AuthProvider/AuthProvider.jsx#L15
Basically, when you are sending a login request from the client (OIDC-client.js), the client sends a unique identifier (State) along with the login request in the URL. The client saves this value in the storage option you choose (local/session). After successful sign-in, server issues tokens in the response redirect url and it also includes the unique identifier client initially sent in login request. Watch the login request url and response url in chrome Developer Tools.
When OIDC Client Library receives the sign-in response, it grabs the unique identifier from the URL and matches with the value it kept in the local/session storage at the time of login request. If they don't match, the client will not accept the token issued by the server.
This is just one level of additional security to make sure, the client is not accepting any tokens issued by any random server or any bookmarked URL.
Hope this helps.!!
usermanager.signinRedirect({ state: { bar: 15 } });
Upvotes: 2