We're attempting to build an app using Angular 1.5 with the new component router bits. We've run into a bit of an edge case and we're wondering if there's any way around it.
The Key Players
- IdentityServer v2: our client uses this for OAuth currently. It causes a part of this problem. It's legacy, and we don't have control over its usage.
- AngularJS 1.5 as our front-end framework.
- The new angular router, called ngComponentRouter now I believe? We figured this style would help us bridge between Angular v1.5 and Angular v2, and it was easy enough to port.
- oauth-ng as a wrapper for our OAuth implicit flow..
- Older browsers: In the sense that we have to support IE9+, meaning we can't use Angular's HTML5 mode.
The Goal
We'd like to take a URL such as http://mysite/#!/auth/#auth_token=xyz123
(structure not under our control, e.g. can't remove second hash) and:
- Get it into an actual auth controller
- Have the auth_token value available, either through parameters or directly through
$location
. (it currently is scrubbed before it ever gets to the controller).
Background / Problem
Our client has a central login system where they're using IdentityServer v2. As far as I understand, when we request a token from IdSrv v2, it responds by appending #auth_token=xyz123
to your redirect URL. It was written back when it thought you'd have my.com/login.html
, thus resulting in login.html#auth_token=xyz123
.
With an Angular app that uses a hash already, though, it becomes a problem, as the URL ends up along the lines of mysite.com/#/auth#auth_token=xyz123
.
This, as you might expect, makes Angular angry. We have yet be able to find a way to get this to work under the component router.
How it Would Work With the Older Routers
Per the oauth-ng docs, if we were using the older router without html5 enabled, we'd do something like the following:
angular.module('app').config(function ($routeProvider) {
$routeProvider
.when('/access_token=:accessToken', {
template: '',
controller: function ($location, AccessToken) {
var hash = $location.path().substr(1);
AccessToken.setTokenFromString(hash);
$location.path('/');
$location.replace();
}
})
What We've Tried
- Defining a component route in a similar way. This didn't work, because
/access_token=:accessToken
contains an=
, which doesn't appear to be allowed by component router. - Seeing if we can get IdentityServer v2 to change the format of the response. It doesn't seem like it's possible; the response seems to be hard-coded to
[URL we define]#auth_token=xyz123
. - Faking out the URL using other hashes, etc. Generally wound up with bad / inconsistent behavior.
What We Think our Options Are
- Use a catch-all / not found controller. If we let the route fall all the way through to
/**
, we can retrieve the token value from$location
. That's sort of gross though; we'd like to avoid it. - Find a way to get the full URL into the controller. We can capture the route and put it through to a controller, but the URL isn't available at that point.
- Go back to using the older router or ui-router (which we'd like not to do at this point).
Anything that could point us in the right direction would be greatly appreciated!
To follow up on this: in the end, we decided that this was a strange enough edge-case that it warranted returning to
ui-router
.While we think the component router makes the most sense, the deciding factor here is that, unfortunately, we don't have 100% control over our routes. The route constraint included the edge case that component-router did not seem capable of handling at the current time.
For those who are working with older oauth server systems, I hope this will serve as a warning / some background as you're making your choice of router.
Hopefully ngComponentRouter will better support this edge case in the future, though I wouldn't blame them for leaving it out.