Oidc-client-js: question on login redirects

Created on 1 Dec 2016  路  14Comments  路  Source: IdentityModel/oidc-client-js

Looking to see if there is a known simple answer to this common case:
i have a spa using angular2
i have id server setup for implicit flow to show the login form and redirect back to my app.

that means that my app is re-loading on the return trip and doe snot have the original state that triggered the request. for most cases that is ok.
if i need to preserve that i can do that in my app for complex logic.

but the simple case is not so clear:
user wants to goto say https://www.mystore.com/customeraccount/123456789
where "/customeraccount/###########" needs a valid user to have rights to access.
the login redirect table can store a few targets but can never store all of them.
so can the oidc-client library stash the real url target in the acr_values and return it back so that when the redireect lands on my app i can then pick that back up and send the user to that view now as an authenticated user ?
how should i load the value before the login request and how should i get the value on the return ?

is there a sample of this that i can take a look at ??

thanks!

question

Most helpful comment

@brockallen
YES!!! now that i am using the right js file and have been able to roud trip the whole process i can verify that i can get back the state data !

@CodeRevver and any others who may want to know this....

when your redirect from the sts server comes back and you call something like:
this ` new UserManager().signinRedirectCallback().then(function (user) {
if (user == null) {
document.getElementById("waiting").style.display = "none";
document.getElementById("error").innerText = "No sign-in request pending.";
}
else {
// Log.default.info("User = " , user );
console.log(" UserManager().signinRedirectCallback() got user " + user.state);

            window.location = "/";
        }
    })
    .catch(function (er) {
        document.getElementById("waiting").style.display = "none";
        document.getElementById("error").innerText = er.message;
    });`

the user.state will have the data you put in at the start of the login call.
so the call to:
this.mgr.signinRedirect({ data: 'abcdef' }).then(function () {
should be such that you replace that string with whatever data / object you need to know where to send the client or the return side.

so if you start with the route they are tyring to get to then on the return site you can route the user back to where they wanted to go.

All 14 comments

The UserManager has a facility to round-trip state for you. You can pass a state param to the signinRedirect and this will be presented back to your app on signinRedirectCallback.

is this what you are refering to:
https://github.com/IdentityModel/oidc-client-js/blob/dev/sample/public/oidc-client-sample.js

i see a "state" getting set on the call to do a sign in.
but how to get that back out when the sign in is completed ??
that i am not seeing in that sample.

Try this:

signinRedirectCallback().then(function(user){
   var your_state = user.state;
});

Any progress?

Sorry I have not yet had a chance to check it out will do so but may be a few days, I am getting good ready to drive to Orlando FL for 360 live where there are training sessions on angular and asp.net core etc... will be there this week and have an angular 2 boot camp on friday.

just got back from my confrence. i am starting to think that the javascript i have has the bug where the variable is called state in some places but data in other places.
i am checking the code here vs the code i have and trying to verify.

ok so here are some of the things i am seeing:
I started from the sample in https://github.com/jmurphzyo/Angular2OidcClient
but it seems to be using an older version of the client code that is smaller in the min.js file.
that file works to login and logout but seem to not handle the data / state that i need.

so i am tying to use the file from the current /dist folder but that gives errors that i am not sure of like this one:
localhost/:26 Error: (SystemJS) AMD module http://localhost:3000/assets/js/oidc/oidc-client.js did not define TypeError: AMD module http://localhost:3000/assets/js/oidc/oidc-client.js did not define at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:232:26) at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:114:43) at http://localhost:3000/node_modules/zone.js/dist/zone.js:502:57 at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:265:35) at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:154:47) at drainMicroTaskQueue (http://localhost:3000/node_modules/zone.js/dist/zone.js:401:35) at XMLHttpRequest.ZoneTask.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:339:25) Error loading http://localhost:3000/assets/js/oidc/oidc-client.js as "oidc-client" from http://localhost:3000/app/shared/services/auth.service.js at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:232:26) at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:114:43) at http://localhost:3000/node_modules/zone.js/dist/zone.js:502:57 at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:265:35) at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:154:47) at drainMicroTaskQueue (http://localhost:3000/node_modules/zone.js/dist/zone.js:401:35) at XMLHttpRequest.ZoneTask.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:339:25) Error loading http://localhost:3000/assets/js/oidc/oidc-client.js as "oidc-client" from http://localhost:3000/app/shared/services/auth.service.js
at one point i got a different error that was saying that a polyfill was not needed / was overwirting one.
seems like the min and non min js files are acting differently for some reason.

will have to look some more and if all else fails i may try to setup a plunker sample so that perhaps someone can see what the problem is... or try and recreate the whole client in Typescript so that i can see what is going on!

Use the lib folder instead of the dist folder for the oidcClient script. Yeah that confused me as well but that should start off your fix.

Here's another reference for you if you need one: https://github.com/CodeRevver/Magnanimous

Also a commit (which you might have to sift through, I wasn't building this expecting people to look at it) -
https://github.com/CodeRevver/Magnanimous/commit/2d003baa83d42eb1b0759c3f8ac2478bba8f0491

@CodeRevver thanks , i will check that out! I think this was said somewhere but the other sample was not doing that and it was working up to a point. but they are using angular-cli and i am using systemjs
and with angular cli i could not see any referecne to the node package, they had a copy of the js file they seemed to be using.

Ok just looked at your code and it looks like we are are the same general path. so here is what i am working on and lets see if you have the answer or if we both need this...

so let's say a user wants to navigate to a view that is a protected url.
so they have a link like https://website.org/customer/account/3456
they need to be redirected to the id server login and that will re-drect them back to the app.
but without some help they do not get the view they want.
so we need to put the url they wanted to go to somewhere and get it back when they return from the login and if they did login route them to the view they were asking for.
in this thread i was told to use the "state" parameter and that it would be saved in storage and i can get it back when the user comes back.
have you tried to make that work ??
it seems that we need to catch the return and check that the state has a URL and then call navigate to the route....

@CodeRevver to clarify a bit look at your https://github.com/CodeRevver/Magnanimous/blob/master/src/Magnanimous.WebUI/app/services/auth/auth.service.ts
line 81 passes { data: 'some data'}
the method at line 87 is not getting the data back out that was passed in....
we are supposed to be able to use that to pass app state to resume the app between the call to login and the login result.

@brockallen
YES!!! now that i am using the right js file and have been able to roud trip the whole process i can verify that i can get back the state data !

@CodeRevver and any others who may want to know this....

when your redirect from the sts server comes back and you call something like:
this ` new UserManager().signinRedirectCallback().then(function (user) {
if (user == null) {
document.getElementById("waiting").style.display = "none";
document.getElementById("error").innerText = "No sign-in request pending.";
}
else {
// Log.default.info("User = " , user );
console.log(" UserManager().signinRedirectCallback() got user " + user.state);

            window.location = "/";
        }
    })
    .catch(function (er) {
        document.getElementById("waiting").style.display = "none";
        document.getElementById("error").innerText = er.message;
    });`

the user.state will have the data you put in at the start of the login call.
so the call to:
this.mgr.signinRedirect({ data: 'abcdef' }).then(function () {
should be such that you replace that string with whatever data / object you need to know where to send the client or the return side.

so if you start with the route they are tyring to get to then on the return site you can route the user back to where they wanted to go.

Looks like my issue is solved so i will close this but for sure some of this info might be good to get into some docs for new angular 2 developers.... use the lib folder, no babel, pass the state and use it to route the view.

Perhaps I was just not having good googlefoo to find a definitive source for this; but this seems like a pretty common scenario and this solution should be elevated in the documentation.

Worth noting on @figuerres solution.

Setting the state here only worked for me when the value was passed as a value to a prop called state:

userManager.signinRedirect({ state: myPassedValue });
Was this page helpful?
0 / 5 - 0 ratings