I'm trying to setup an angular 1 app using oidc-client-js to automatically check if a user is logged in or not.
When the user is not logged, the redirection works well, but when it comes back to the application, it ends up in an infinite loop because getUser() always return null.
Here the code I use on application load:
.run(['oidcManager', '$log', function (oidcManager, $log) {
var userManager = oidcManager.userManager;
Oidc.Log.logger = $log;
Oidc.Log.level = Oidc.Log.INFO;
userManager.getUser().then(function (user) {
$log.debug('getUser returned', user);
if (!user) {
userManager.signinRedirect().then(function() {
$log.debug("signinRedirect done");
}).catch(function(err) {
$log.debug(err);
});
} else {
$log.debug('user', user);
}
});
But on the logs, I always have
UserManager.getUser
_loadUser
WebStorageStateStore.get user:xxx
no user storageString
user not found in storage
getUser returned null
UserManager.signinRedirect
then logs corresponding to the logging process and then that comes back to getUser and doesn't find it.
When I look in the storage, I can see entries for user, but on the localStorage, not on the sessionStorage, even if I didn't set the userStore option on UserManager constructor.
Is there something wrong with getUser() method? or something wrong in the way I use the lib?
By the way, oidcManager is just a factory wrapping the UserManager like that:
```
angular.module('myApp')
.factory('oidcManager', function ($log) {
var config = {
authority: "http://myAuthority",
client_id: "clientId",
redirect_uri: "https://localhost:44309/",
response_type: "id_token token",
scope: "openid profile offline_access custom"
},
userManager = new Oidc.UserManager(config);
userManager.events.addAccessTokenExpiring(function () {
$log.debug("token expiring");
});
userManager.events.addAccessTokenExpired(function () {
$log.debug("token expired");
});
userManager.events.addSilentRenewError(function (e) {
$log.debug("silent renew error", e.message);
});
userManager.events.addUserLoaded(function (user) {
$log.debug("user loaded", user);
userManager.getUser().then(function () {
$log.debug("getUser loaded user after userLoaded event fired");
});
});
userManager.events.addUserUnloaded(function (e) {
$log.debug("user unloaded");
});
return {
userManager: userManager
};
});
```
userManager.getUser().then(function () {
$log.debug("getUser loaded user after userLoaded event fired");
});
should be:
userManager.getUser().then(function (user) {
if (user) // user is logged in
else // user is not logged
});
Yes, it's what I have:
userManager.getUser().then(function (user) {
$log.debug('getUser returned', user);
if (!user) {
//not logged
} else {
//logged
}
and if I reverse the logic like that I have the same result:
userManager.getUser().then(function (user) {
if (user) {
$log.debug('user', user);
} else {
userManager.signinRedirect().then(function() {
$log.debug("signinRedirect done");
}).catch(function(err) {
$log.debug(err);
});
}
});
So I think there something wrong with getUser(), because using signinRedirectCallback() that works:
userManager.signinRedirectCallback().then(function (user) {
$log.debug("signinRedirectCallback done", user);
}).catch(function (err) {
$log.error('error while signinRedirectCallback', err);
userManager.signinRedirect().then(function() {
$log.debug("signinRedirect done");
}).catch(function (err) {
$log.error('error while signinRedirect', err);
});
});
Not sure then, you will have to do some debugging.
Might be related https://github.com/IdentityModel/oidc-client-js/issues/288
we also have similar issue when getUser returns null, but didn't have enough time to investigate it
@mathilde-pellerin any update?
Sorry, I didn't have time to investigate neither. I use this workaround which is less clean than getUser() but works:
signIn: function () {
return $q(function (resolve, reject) {
userManager.signinRedirectCallback().then(function () {
resolve();
}).catch(function (err) {
$log.debug('User not logged', err);
userManager.signinRedirect().then(function () {
$log.debug("signinRedirect done");
resolve();
}).catch(function (err) {
reject();
$log.error('error while signinRedirect', err);
});
});
});
}
Encountering the same problem now. Will try to investigate more.
I get this error in the console 'user not found in storage'
You have to use both, the signinRedirect and the signinRedirectCallback. First you have to do something like that:
this.mgr.signinRedirect().then(function () {
console.log('signinRedirect done');
}).catch(function (err) {
console.log(err);
});
And when the IDS redirects to your Website, the token and some info is returned as fragment in the URL. You have to pass this fragment to the signinRedirectCallback method, like that:
this.mgr.signinRedirectCallback(url).then(function (loggedUser) {
///// the logged user contains the user info
});
Now, the user is created in the user store and you can use getUser and all the provided functionality.
@franpsif thanks!
The part of putting the url here this.mgr.signinRedirectCallback(url) helped me move forward. :)
They do not show this in the official samples @franpsif https://github.com/IdentityServer/IdentityServer4.Samples/blob/release/Clients/src/JsOidc/wwwroot/app.js#L152
By default it gets window.location.url... https://github.com/IdentityModel/oidc-client-js/blob/dev/src/UserManager.js#L289 then https://github.com/IdentityModel/oidc-client-js/blob/dev/src/RedirectNavigator.js#L23
Most helpful comment
You have to use both, the signinRedirect and the signinRedirectCallback. First you have to do something like that:
And when the IDS redirects to your Website, the token and some info is returned as fragment in the URL. You have to pass this fragment to the signinRedirectCallback method, like that:
Now, the user is created in the user store and you can use getUser and all the provided functionality.