title: Get hash url parameters to redirect to requesting url when using Auth0 with Angular 2
body: <p>Auth0 requires you to whitelist callback URLs after authentication so you can't just login on any page in your application with URLs like /thing/1, /thing/1001 as there's no way to wildcard the thing IDs.</p>
  
  <p>This <a href="https://github.com/auth0/wp-auth0/issues/29#issuecomment-252040395" rel="nofollow noreferrer">Github conversation</a> points to neat solution which I have interpreted in Angular 2 as:</p>
  
  <p>In my auth.service.ts:</p>
  
  <pre><code>lock = new Auth0Lock('Client_ID', 'Domain', {
          auth: {
              redirectUrl: window.location.origin + '/login',
              responseType: 'token',
              params: {
                  scope: 'openid name email',
                  state: JSON.stringify({pathname: window.location.pathname})
              }
          }
      });
  </code></pre>
  
  <p>I can then whitelist my /login route in Angular 2. I tried getting my login.component.ts to read and then navigate to the pathname returned by Auth0 in the call back like this:</p>
  
  <pre><code>this.route
      .queryParams
      .subscribe(params =&gt; {
           this.state = params['state'];
           this.router.navigate(this.state, {preserveQueryParams: true});
       });
  </code></pre>
  
  <p>...but params always seems to be empty. As far as I can tell this is because the call back URL is of this form:</p>
  
  <p><a href="http://localhost:5555/login#access_token=...&amp;id_token=...&amp;token_type=Bearer&amp;state=%7B%22pathname%22%3A%22%2Flogin%22%7D" rel="nofollow noreferrer">http://localhost:5555/login#access_token=...&amp;id_token=...&amp;token_type=Bearer&amp;state=%7B%22pathname%22%3A%22%2Flogin%22%7D</a></p>
  
  <p>...and Angular 2 routing automatically strips off the # parameters before they get to the LoginComponent.</p>
  
  <p>I then spotted that authResult on lock.authenticated still contains my state parameter in auth.service.ts so attempted to navigate to it as follows:</p>
  
  <pre><code>this.lock.on("authenticated", (authResult:any) =&gt; {
      localStorage.setItem('id_token', authResult.idToken);
      let state: string = JSON.parse(authResult.state);
      this.router.navigate([state.pathname], {});
  </code></pre>
  
  <p>This seemed to work initially but, it turns out, not reliably...it seems to redirect me unpredictably anywhere from </p>
  
  <pre><code>/thing/1001 to 
  /things or even 
  /
  </code></pre>
  
  <p>...and I can't work out why. Any help very much appreciated.</p>
  
  <p><strong>EDIT In response to @shusson's answer:</strong></p>
  
  <p>Working code based on @shusson's answer is in auth.service.ts:</p>
  
  <pre><code>export class Auth {
      // Configure Auth0
      lock = new Auth0Lock('Client_ID', 'Domain',{
          auth: {
              redirectUrl: location.origin + '/login',
              responseType: 'token',
          }
      });
  
      constructor(private router: Router, route: ActivatedRoute) {
  
          // Add callback for lock `authenticated` event
          this.lock.on("authenticated", (authResult:any) =&gt; {
              localStorage.setItem('id_token', authResult.idToken);
              let state: any = JSON.parse(authResult.state);
              this.router.navigate([state.pathname], {});
          ...
       }
  
      public login() {
          // Call the show method to display the widget.
          this.lock.show({
              auth: {
                  params: {
                      scope: 'openid name email',
                      state: JSON.stringify({pathname: this.router.url})
                  }
              }
          });
      };
  </code></pre>
  
  <p><strong>EDIT: based on <a href="https://auth0.com/forum/t/redirect-with-call-back-hash-url-parameters-angular-2/4420/2?u=theotherdy" rel="nofollow noreferrer">this comment</a> re: passing paths in callback being a CSRF vulnerability:</strong></p>
  
  <p>Final working code in my auth.service.ts is:</p>
  
  <pre><code>import { Injectable }      from '@angular/core';
  import { tokenNotExpired } from 'angular2-jwt/angular2-jwt';
  import { Router, ActivatedRoute } from '@angular/router';
  import { UUID } from 'angular2-uuid/index';
  
  // Avoid name not found warnings
  declare var Auth0Lock: any;
  
  @Injectable()
  export class Auth {
      // Configure Auth0
      lock = new Auth0Lock('Client_ID', 'Domain',{
          auth: {
              redirectUrl: location.origin + '/login',
              responseType: 'token',
          }
      });
      //Store profile object in auth class
      userProfile: Object;
  
      constructor(private router: Router, route: ActivatedRoute) {
  
          // Set userProfile attribute of already saved profile
          this.userProfile = JSON.parse(localStorage.getItem('profile'));
  
          // Add callback for lock `authenticated` event
          this.lock.on("authenticated", (authResult:any) =&gt; {
              localStorage.setItem('id_token', authResult.idToken);
              let pathname_object: any = JSON.parse(authResult.state);
              let pathname: any = localStorage.getItem(pathname_object.pathname_key);
              //get rid of localStorage of url
              localStorage.removeItem(pathname_object.pathname_key);
              //navigate to original url
              this.router.navigate([pathname], {});
  
          // Fetch profile information
          this.lock.getProfile(authResult.idToken, (error:any, profile:any) =&gt; {
              if (error) {
                  // Handle error
                  alert(error);
                  return;
              }
  
              localStorage.setItem('profile', JSON.stringify(profile));
                  this.userProfile = profile;
              });
          });
      }
  
      public login() {
          //generate UUID against which to store path
          let uuid = UUID.UUID();
          localStorage.setItem(uuid, this.router.url);
          // Call the show method to display the widget.
          this.lock.show({
              auth: {
                  params: {
                      scope: 'openid name email',
                      state: JSON.stringify({pathname_key: uuid})
                  }
              }
          });
      };
  ...
  }
  </code></pre>