0

I have an Angular2/TypeScript app I'm working on. I'm using Implicit Auth with an OAuth 2.0 service for authentication. The browser redirects the user to the OAuth endpoint to log into their account, and is then redirected back to my app as per the spec. The redirect contains the access token as part of the URI parameters. This access token contains special characters which are URL-Encoded by the browser, so I have to decode the token before I can pass it to the OAuth service for authentication.

Here's a sample (encoded) token that has long since expired: 1468463839895.39e131aa-7a82-4267-b126-c087d6abe515.285ae51e-41b4-4f88-ba64-d968b20f2dde.39400b6b-47f3-4585-b51f-bd3c5c8953c7%3B1.MCwCFBxaflXgZrxvuGa5D3vM%2FnFustT9AhQWlix2a3Lb9Yj9i9lo8ICR27HvxA%3D%3D

After splitting query strings by hand, to get the token, I then simply call decodeURIComponent(access_token), and I'm presented with the same un-decoded token again. It does not seem to work.

However, if I place a breakpoint, copy the encoded token, and execute the following in my JS console, it works:

decodeURIComponent('1468463839895.39e131aa-7a82-4267-b126-c087d6abe515.285ae51e-41b4-4f88-ba64-d968b20f2dde.39400b6b-47f3-4585-b51f-bd3c5c8953c7%3B1.MCwCFBxaflXgZrxvuGa5D3vM%2FnFustT9AhQWlix2a3Lb9Yj9i9lo8ICR27HvxA%3D%3D')

What gives? It doesn't work with a variable through my code, but if I inspect my variable value, and use it manually again in the console, it works. I don't get any exceptions thrown at me.

I've also tried splitting the token with .split('.') and then decoding each piece, but that also just returns the same input value.

Below is more code for context. I use an Angular 2 Guard on a route.

In my guard service:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    let url: string = state.url;
    return this.checkLogin(url);
}

checkLogin(url: string): boolean {
    if (this.authService.accessToken) {
        return true;
    }
    else if (url.indexOf('#access_token') > -1) {
        this.authService.processAccessTokenUrl(url);
        this.authService.afterLoginRedirect();
    }
    else {
        // Navigate to the login page
        this.authService.login();
        return false;
    }
}

and in my AuthService:

login(): void {
    window.location.href = this.OAuthUrl;
}
afterLoginRedirect(): void {
    this.router.navigate(['/dashboard']);
}
processAccessTokenUrl(url: string): void {
    this.responseParts = url.split('&');
    if (this.responseParts[0].indexOf('access_token') > -1) {
        let ndxEql = this.responseParts[0].indexOf('=') + 1;
        let access_token = this.responseParts[0].substr(ndxEql, this.responseParts[0].length - ndxEql);
        if (access_token.length > 0) {
            this.accessToken = decodeURIComponent(access_token);

            // THIS IS WHERE THE PROBLEM IS - BOTH LOG THE SAME OUTPUT
            console.log('accessToken RAW', access_token);
            console.log('accessToken DECODED', this.accessToken);
        }
    }
}
Krummelz
  • 1,046
  • 1
  • 11
  • 23

2 Answers2

2

So I realised that after decoding the value, it still had '%' characters in, but the output did look every-so-slightly different from the input. So I just chained the same thing a few times, and now it works:

decodeURIComponent(decodeURIComponent(decodeURIComponent(access_token)))

...great

Krummelz
  • 1,046
  • 1
  • 11
  • 23
0

It's the hack to emulate decode from constant:

var result = eval('decodeURI("'+text+'")');