{"id":823,"date":"2016-03-01T18:54:00","date_gmt":"2016-03-01T18:54:00","guid":{"rendered":"https:\/\/ionic.io\/blog\/?p=823"},"modified":"2016-04-14T20:24:47","modified_gmt":"2016-04-14T20:24:47","slug":"ionic-2-and-auth0","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0","title":{"rendered":"Ionic 2 and Auth0"},"content":{"rendered":"<blockquote><p>\n  <strong>TL;DR:<\/strong> Implementing modern authentication and identity can be tricky. Fortunately, Auth0 makes it really easy to get up and running quickly and without any friction. With Auth0 you can use <a href=\"https:\/\/auth0.com\/learn\/social-login\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">any social identity provider<\/a> and have features like <a href=\"https:\/\/auth0.com\/learn\/get-started-with-mfa\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">multifactor authentication<\/a>, <a href=\"https:\/\/auth0.com\/learn\/how-to-implement-single-sign-on\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">single sign-on<\/a>, and more, all at the flip of a switch. In this tutorial we&#8217;ll implement authentication in an Ionic 2 app and show how to use refresh tokens. Check out the <a href=\"https:\/\/github.com\/auth0\/auth0-ionic2\/\">repo<\/a> to go straight to the code.\n<\/p><\/blockquote>\n<p>Implementing authentication isn&#8217;t quite as simple as it used to be. Features like <a href=\"https:\/\/auth0.com\/learn\/social-login\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">social login<\/a>, <a href=\"https:\/\/auth0.com\/learn\/get-started-with-mfa\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">multifactor authentication<\/a>, and <a href=\"https:\/\/auth0.com\/learn\/how-to-implement-single-sign-on\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">single sign-on<\/a> are complicated, error-prone, and generally tough to write from scratch. It&#8217;s doable, but it&#8217;s time consuming. Instead of worrying about those details, we should be focusing on our application&#8217;s business logic. With Auth0, we can.<\/p>\n<p>Auth0 loves Angular and Ionic, and that&#8217;s why we&#8217;ve created several libraries for them that make it easy to handle authentication with JSON Web Tokens. Today we&#8217;ll see how easy it is to use one of those libraries called <strong><a href=\"https:\/\/github.com\/auth0\/angular2-jwt\">angular2-jwt<\/a><\/strong> along with Auth0 to make authentication a breeze.<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" \/><\/noscript><\/noscript><\/p>\n<h2>Getting Started<\/h2>\n<p>To get started, sign up for your <a href=\"https:\/\/auth0.com\/signup\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">free Auth0 account<\/a>. With Auth0&#8217;s free plan you can have up to 7,000 regular active users and use two social identity providers. A user is considered active if they&#8217;ve logged in some time in the last 30 days. This is huge, especially considering that most companies only have 15% of their userbase active at a time.<\/p>\n<p>Auth0 issues a <a href=\"http:\/\/jwt.io\/introduction\">JSON Web Token (JWT)<\/a> on every login, which is the perfect solution for protecting your data API.<\/p>\n<p>It&#8217;s assumed that you already have an Ionic 2 app going. If you don&#8217;t, follow the <a href=\"http:\/\/ionicframework.com\/docs\/v2\/getting-started\/\">getting started guide<\/a> to get up and running.<\/p>\n<h2>Add the Dependencies<\/h2>\n<p>The only dependency from NPM outside of a regular Ionic 2 installation we&#8217;ll need is angular2-jwt. We developed this library to help with sending authenticated HTTP requests and also to provide a utility for decoding JWTs.<\/p>\n<pre><code class=\"bash\">npm install angular2-jwt\n<\/code><\/pre>\n<p>We also need the <strong>Auth0Lock<\/strong> library to use the Lock widget. This can be added to the <code>index.html<\/code> file.<\/p>\n<pre><code class=\"html\">  ...\n\n  &lt;!-- Auth0 Lock script --&gt;\n  &lt;script src=&quot;https:\/\/cdn.auth0.com\/js\/lock-9.0.min.js&quot;&gt;&lt;\/script&gt;\n\n  &lt;!-- Setting the right viewport --&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no&quot; \/&gt;\n\n  ...\n<\/code><\/pre>\n<h2>Configure angular2-jwt<\/h2>\n<p>We need to configure angular2-jwt in the <code>providers<\/code> array of our <code>@App<\/code> decorator. For this, we&#8217;ll need to bring in <code>provide<\/code> from <code>angular2\/core<\/code> as well.<\/p>\n<pre><code class=\"js\">\/\/ app\/app.ts\n\nimport {App, Platform} from &#039;ionic-angular&#039;;\nimport {TabsPage} from &#039;.\/pages\/tabs\/tabs&#039;;\nimport {provide} from &#039;angular2\/core&#039;;\nimport {Http} from &#039;angular2\/http&#039;\nimport {AuthHttp, AuthConfig} from &#039;angular2-jwt&#039;;\nimport {Type} from &#039;angular2\/core&#039;;\nimport {AuthService} from &#039;.\/services\/auth\/auth&#039;;\n\n\n@App({\n  template: &#039;&lt;ion-nav [root]=&quot;rootPage&quot;&gt;&lt;\/ion-nav&gt;&#039;,\n  config: {},\n  providers: [\n    provide(AuthHttp, {\n      useFactory: (http) =&gt; {\n        return new AuthHttp(new AuthConfig(), http);\n      },\n      deps: [Http]\n    }),\n    AuthService\n  ]\n})\n\n...\n<\/code><\/pre>\n<h2>Create an Authentication Service<\/h2>\n<p>For this simple demo app, the user will only be able to log in from the profile page; however, we should make our authentication logic flexible such that it can be used in other places within the app too. For this, its best if we extract authentication to its own service and then inject that service wherever necessary.<\/p>\n<p>Let&#8217;s create <code>AuthService<\/code> in <code>app\/services\/auth\/auth.ts<\/code><\/p>\n<pre><code class=\"js\">\/\/ app\/services\/auth\/auth.ts\n\nimport {Storage, LocalStorage} from &#039;ionic-angular&#039;;\nimport {AuthHttp, JwtHelper, tokenNotExpired} from &#039;angular2-jwt&#039;;\nimport {Injectable} from &#039;angular2\/core&#039;;\nimport {Observable} from &#039;rxjs\/Rx&#039;;\n\n\/\/ Avoid name not found warnings\ndeclare var Auth0Lock: any;\n\n@Injectable()\nexport class AuthService {\n  jwtHelper: JwtHelper = new JwtHelper();\n  lock = new Auth0Lock(AUTH0_CLIENT_ID, AUTH0_DOMAIN);\n  local: Storage = new Storage(LocalStorage);\n  user: Object;\n\n  constructor(private authHttp: AuthHttp) {\n    \/\/ If there is a profile saved in local storage\n    this.local.get(&#039;profile&#039;).then(profile =&gt; {\n      this.user = JSON.parse(profile);\n    }).catch(error =&gt; {\n      console.log(error);\n    });\n  }\n\n  public authenticated() {\n    \/\/ Check if there&#039;s an unexpired JWT\n    return tokenNotExpired();\n  }\n\n  public login() {\n    \/\/ Show the Auth0 Lock widget\n    this.lock.show({\n      authParams: {\n        scope: &#039;openid offline_access&#039;,\n        device: &#039;Mobile device&#039;\n      }\n    }, (err, profile, token, accessToken, state, refreshToken) =&gt; {\n      if (err) {\n        alert(err);\n      }\n      \/\/ If authentication is successful, save the items\n      \/\/ in local storage\n      this.local.set(&#039;profile&#039;, JSON.stringify(profile));\n      this.local.set(&#039;id_token&#039;, token);\n      this.local.set(&#039;refresh_token&#039;, refreshToken);\n      this.user = profile;\n    });    \n  }\n\n  public logout() {\n    this.local.remove(&#039;profile&#039;);\n    this.local.remove(&#039;id_token&#039;);\n    this.local.remove(&#039;refresh_token&#039;);\n    this.user = null;\n  }\n}\n<\/code><\/pre>\n<p>We&#8217;ve got an <code>authenticated<\/code> method returning a call to <code>tokenNotExpired<\/code> which will check whether there is an unexpired JWT in local storage. From a client side perspective, this will be the determining factor for whether the user is logged in or not.<\/p>\n<p>We&#8217;ve set up an instance of the Lock widget at the top and this is where you need to supply your own Auth0 credentials. The <code>login<\/code> method makes a call to <code>lock.show<\/code> and if authentication is successful, it saves the user&#8217;s profile, JWT, and refresh token in local storage. The JWT (which is named <code>id_token<\/code>) is what we&#8217;ll attach as an <code>Authorization<\/code> header in HTTP requests, and the <code>refresh_token<\/code> will be used to get a new JWT when the current one expires. We&#8217;ll set up the refreshing a little later.<\/p>\n<p>The <code>logout<\/code> method simply removes these items from local storage and sets the <code>user<\/code> property to <code>null<\/code>, which is all we need to do to log the user out on the client side.<\/p>\n<h2>Create the Profile Page<\/h2>\n<p>With the <code>AuthService<\/code> in place, let&#8217;s put in the profile page. Create a new folder in the <code>pages<\/code> directory and give it both a <code>profile.html<\/code> and a <code>profile.ts<\/code> file.<\/p>\n<blockquote><p>\n  <strong>Tip:<\/strong> You can also generate page folders and files automatically from the command line with <code>ionic g page profile<\/code>\n<\/p><\/blockquote>\n<p>Now in <code>profile.ts<\/code> we can set up the page.<\/p>\n<pre><code class=\"js\">\/\/ app\/pages\/profile\/profile.ts\n\nimport {Page} from &#039;ionic-angular&#039;;\nimport {AuthService} from &#039;..\/..\/services\/auth\/auth&#039;;\n\n@Page({\n  templateUrl: &#039;build\/pages\/profile\/profile.html&#039;,\n})\nexport class ProfilePage {\n\n  \/\/ We need to inject AuthService so that we can\n  \/\/ use it in the view\n  constructor(private auth: AuthService) {}\n}\n<\/code><\/pre>\n<p>The <code>AuthService<\/code> just needs to be injected in the constructor and we&#8217;ll be able to use it in the template.<\/p>\n<p>The template should show a simple contact card with the user&#8217;s details if they are authenticated.<\/p>\n<pre><code class=\"html\">  &lt;!-- app\/pages\/profile\/profile.html --&gt;\n\n  &lt;ion-navbar *navbar&gt;\n    &lt;ion-title&gt;Profile&lt;\/ion-title&gt;\n  &lt;\/ion-navbar&gt;\n\n  &lt;ion-content padding *ngIf=&quot;!auth.authenticated()&quot;&gt;\n\n    &lt;button block (click)=&quot;auth.login()&quot;&gt;Login&lt;\/button&gt;\n\n  &lt;\/ion-content&gt;\n\n  &lt;ion-content padding *ngIf=&quot;auth.authenticated()&quot;&gt;  \n\n    &lt;ion-card&gt;\n\n      &lt;ion-item *ngIf=&quot;auth.user&quot;&gt;\n        &lt;ion-avatar item-left&gt;\n          &lt;img src=&quot;{{ auth.user.picture }}&quot;&gt;\n        &lt;\/ion-avatar&gt;\n        &lt;h2&gt;{{ auth.user.nickname }}&lt;\/h2&gt;\n        &lt;p&gt;{{ auth.user.email }}&lt;\/p&gt;\n      &lt;\/ion-item&gt;\n\n    &lt;\/ion-card&gt;\n\n    &lt;button block (click)=&quot;auth.logout()&quot;&gt;Logout&lt;\/button&gt;\n\n  &lt;\/ion-content&gt;\n<\/code><\/pre>\n<p>Now let&#8217;s try logging in! You can either create a user in your Auth0 dashboard, or you can sign one up from the Lock widget.<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" alt=\"ionic2 authentication lock widget\" \/><\/noscript><\/noscript><\/p>\n<p>The data returned in <code>profile<\/code> by Auth0 is nicely formatted and normalized across identity providers, which is very great for easily accessing properties like the user&#8217;s avatar, name, and email. Here is the JSON that is returned when I log in with standard username and password:<\/p>\n<pre><code class=\"js\">{\n  &quot;email&quot;:&quot;ryan.chenkie@auth0.com&quot;,\n  &quot;picture&quot;:&quot;https:\/\/s.gravatar.com\/avatar\/a471a41d23efb638d79e3138eaedba50?s=480&amp;r=pg&amp;d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fry.png&quot;,&quot;name&quot;:&quot;ryan.chenkie@auth0.com&quot;,\n  &quot;nickname&quot;:&quot;ryan.chenkie&quot;,\n  &quot;app_metadata&quot;: { \n    &quot;roles&quot;: [&quot;user&quot;]\n  },\n  &quot;roles&quot;: [&quot;user&quot;],\n  &quot;email_verified&quot;: true,\n  &quot;clientID&quot;:&quot;{clientId}&quot;,\n  &quot;updated_at&quot;:&quot;2016-02-25T18:05:59.398Z&quot;,\n  &quot;user_id&quot;:&quot;auth0|{userId}&quot;,\n  &quot;identities&quot;: [{\n    &quot;user_id&quot;:&quot;{userId}&quot;,\n    &quot;provider&quot;:&quot;auth0&quot;,\n    &quot;connection&quot;:&quot;Username-Password-Authentication&quot;,\n    &quot;isSocial&quot;:false\n  }],\n  &quot;created_at&quot;:\n  &quot;2016-02-18T18:11:21.679Z&quot;,\n  &quot;global_client_id&quot;:&quot;{globalClientId}&quot;\n}\n<\/code><\/pre>\n<h2>Make Authenticated HTTP Requests<\/h2>\n<p>With the user&#8217;s JWT in local storage, we can now make authenticated calls to our server. Auth0 has SDKs for nearly all popular backend frameworks and languages. Find the one that&#8217;s right for you in <a href=\"https:\/\/auth0.com\/docs\/quickstart\/backend\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">the docs<\/a> and set up your secret key on your server to protect your API.<\/p>\n<p>Let&#8217;s create a simple page called <code>ping<\/code> that will send HTTP requests.<\/p>\n<pre><code class=\"js\">\/\/ app\/pages\/ping\/ping.ts\n\nimport {Page} from &#039;ionic-angular&#039;;\nimport {Http} from &#039;angular2\/http&#039;;\nimport {AuthHttp} from &#039;angular2-jwt&#039;;\nimport {AuthService} from &#039;..\/..\/services\/auth\/auth&#039;;\nconst map = require(&#039;rxjs\/add\/operator\/map&#039;);\n\n@Page({\n  templateUrl: &#039;build\/pages\/ping\/ping.html&#039;,\n})\nexport class PingPage {\n  message: string;\n  error: string;\n\n  constructor(private http: Http, private authHttp: AuthHttp, private auth: AuthService) {\n\n  }\n\n  ping() {\n    \/\/ Change the endpoint up for\n    \/\/ one that points to your own server.\n    this.http.get(&#039;http:\/\/example.com\/ping&#039;)\n      .map(res =&gt; res.json())\n      .subscribe(\n        data =&gt; this.message = data,\n        err =&gt; this.error = err\n      );\n  }\n\n  securedPing() {\n    \/\/ Here we use authHttp to make an authenticated\n    \/\/ request to the server. Change the endpoint up for\n    \/\/ one that points to your own server.\n    this.authHttp.get(&#039;http:\/\/example.com\/secured\/ping&#039;)\n      .map(res =&gt; res.json())\n      .subscribe(\n        data =&gt; this.message = data,\n        err =&gt; this.error = err\n      );\n  }\n\n}\n<\/code><\/pre>\n<p>The <code>securedPing<\/code> method uses the <code>AuthHttp<\/code> class from <strong>angular2-jwt<\/strong> which automatically attaches the user&#8217;s JWT as an <code>Authorization<\/code> header.<\/p>\n<h2>Enable Multi-Factor Authentication<\/h2>\n<p>Enabling two-step authentication for your app is easy. Head over to the <strong>Multifactor Auth<\/strong> link in your dashboard and flip the switch to &#8220;on&#8221;. You&#8217;ll be presented with a code snippet to edit where you need to add the <code>clientId<\/code> of any apps you want to enable multi-factor auth for. Finally, select a provider (either Google Authenticator or Duo) and you&#8217;re good to go!<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-enable-mfa.png\" alt=\"ionic2 authentication mfa\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-enable-mfa.png\" alt=\"ionic2 authentication mfa\" \/><\/noscript><\/p>\n<p>Now when your users log in they will need to use Google Authenticator and provide an access code.<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-mfa.png\" alt=\"ionic2 authentication mfa\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-mfa.png\" alt=\"ionic2 authentication mfa\" \/><\/noscript><\/p>\n<p>By default, the user won&#8217;t need to use multifactor authentication again for 30 days. This can be changed by uncommenting <code>ignoreCookie: true<\/code> in the rule above.<\/p>\n<h2>Set Up Token Refreshing<\/h2>\n<p>Refresh tokens are special tokens that can be used to get a new JWT for the user. We&#8217;ve already saved the user&#8217;s refresh token in local storage when they successfully authenticated, so now we have to set up some logic to automatically grab a new JWT at the right time.<\/p>\n<p>In Angular 1.x, the recommended approach for retreiving a new JWT with a refresh token is to add some logic to an <a href=\"https:\/\/github.com\/auth0\/angular-jwt#using-promises-on-the-tokengetter-refresh-token-example\/\">HTTP interceptor<\/a> that checks if the JWT is expired and sends a request for a new token if it is. Angular 2 doesn&#8217;t have the same concept of global interceptors that can modify behavior when a request is made, so we have to take a different approach.<\/p>\n<p>There are a couple different ways we could implement token refreshing in Angular 2 and today we&#8217;ll see how to use observables to set up scheduled refreshing. Basically we want to create a method called <code>scheduleRefresh<\/code> that will be run when the user logs in. It will find out how long the JWT is valid for and will schedule a refresh at the appropriate time.<\/p>\n<pre><code class=\"js\">\/\/ app\/services\/auth\/auth.ts\n\nexport class AuthService {\n  ...\n  refreshSubscription: any;\n\n  ...\n\n  public scheduleRefresh() {\n    \/\/ If the user is authenticated, use the token stream\n    \/\/ provided by angular2-jwt and flatMap the token\n    let source = this.authHttp.tokenStream.flatMap(\n      token =&gt; {\n        \/\/ The delay to generate in this case is the difference\n        \/\/ between the expiry time and the issued at time\n        let jwtIat = this.jwtHelper.decodeToken(token).iat;\n        let jwtExp = this.jwtHelper.decodeToken(token).exp;\n        let iat = new Date(0);\n        let exp = new Date(0);\n\n        let delay = (exp.setUTCSeconds(jwtExp) - iat.setUTCSeconds(jwtIat));\n\n        return Observable.interval(delay);\n      });\n\n    this.refreshSubscription = source.subscribe(() =&gt; {\n      this.getNewJwt();\n    });\n  }\n\n  public startupTokenRefresh() {\n    \/\/ If the user is authenticated, use the token stream\n    \/\/ provided by angular2-jwt and flatMap the token\n    if (this.authenticated()) {\n      let source = this.authHttp.tokenStream.flatMap(\n        token =&gt; {\n          \/\/ Get the expiry time to generate\n          \/\/ a delay in milliseconds\n          let now: number = new Date().valueOf();\n          let jwtExp: number = this.jwtHelper.decodeToken(token).exp;\n          let exp: Date = new Date(0);\n          exp.setUTCSeconds(jwtExp);\n          let delay: number = exp.valueOf() - now;\n\n          \/\/ Use the delay in a timer to\n          \/\/ run the refresh at the proper time\n          return Observable.timer(delay);\n        });\n\n       \/\/ Once the delay time from above is\n       \/\/ reached, get a new JWT and schedule\n       \/\/ additional refreshes\n       source.subscribe(() =&gt; {\n         this.getNewJwt();\n         this.scheduleRefresh();\n       });\n    }\n  }\n\n  public unscheduleRefresh() {\n    \/\/ Unsubscribe fromt the refresh\n    if (this.refreshSubscription) {\n      this.refreshSubscription.unsubscribe();\n    }\n  }\n\n  public getNewJwt() {\n    \/\/ Get a new JWT from Auth0 using the refresh token saved\n    \/\/ in local storage\n    this.local.get(&#039;refresh_token&#039;).then(token =&gt; {\n      this.lock.getClient().refreshToken(token, (err, delegationRequest) =&gt; {\n        if (err) {\n          alert(err);\n        }\n        this.local.set(&#039;id_token&#039;, delegationRequest.id_token);\n      });\n    }).catch(error =&gt; {\n      console.log(error);\n    });\n  }\n}\n<\/code><\/pre>\n<p>There&#8217;s quite a bit going on here, so let&#8217;s break it down by method.<\/p>\n<ol>\n<li><code>scheduleRefresh<\/code> &#8211; angular2-jwt provides an observable with the user&#8217;s JWT and here we are using <code>flatMap<\/code> to access it and find out how long it is valid for. We&#8217;re then returning a new observable with an interval equal to this amount of time as the <code>delay<\/code> and subscribing to it so we can call the method for getting the new JWT after that amount of time.<\/p>\n<\/li>\n<li>\n<p><code>startupTokenRefresh<\/code> &#8211; the amount of time that we use for our interval in the <code>scheduleRefresh<\/code> method is for cases where we have a &#8220;fresh&#8221; token, or in other words, the token we get when the user first logs in. We also need to consider cases when the user comes back to the app after closing it. In this case, the app&#8217;s state will be refreshed, so we&#8217;ll need to find out if there is an unexpired JWT in local storage, and if so, we&#8217;ll need to schedule a refresh. This refresh will be a bit different though. The amount of time to wait before refreshing will be less than if we have a &#8220;fresh&#8221; token. We&#8217;ll also only want to do one of these &#8220;startup&#8221; refreshing once, so we use an <code>Observable.timer<\/code> instead of <code>Observable.interval<\/code>. When we subscribe to the source observable in this method, we get the new JWT and we also call <code>scheduleRefresh<\/code> to set up further refreshing.<\/p>\n<\/li>\n<li>\n<p><code>unscheduleRefresh<\/code> &#8211; when the user logs out, we want to unsubscribe from any token refreshing<\/p>\n<\/li>\n<li>\n<p><code>getNewJwt<\/code> &#8211; we can use <code>lock.getClient().refreshToken<\/code> to send a request to the <code>\/delegation<\/code> endpoint. If this endpoint receives a valid refresh token, it will return a new JWT.<\/p>\n<\/li>\n<\/ol>\n<p>Now we need to adjust the <code>login<\/code> and <code>logout<\/code> methods to use these new methods.<\/p>\n<pre><code class=\"js\">\/\/ app\/services\/auth\/auth.ts\n\n...\n\npublic login() {\n  \/\/ Show the Auth0 Lock widget\n  this.lock.show({\n    ...\n\n  }, (err, profile, token, accessToken, state, refreshToken) =&gt; {\n    if (err) {\n      alert(err);\n    }\n    ...\n\n    \/\/ Schedule a token refresh\n    this.scheduleRefresh();\n  });    \n}\n\npublic logout() {    \n  ...\n\n  \/\/ Unschedule the token refresh\n  this.unscheduleRefresh();\n}\n\n...\n<\/code><\/pre>\n<p>Finally, we need to call <code>startupTokenRefresh<\/code> when the app is ready.<\/p>\n<pre><code class=\"js\">\/\/ app\/app.ts\n\n...\n\nexport class MyApp {\n  rootPage: Type = TabsPage;\n\n  constructor(platform: Platform, private authHttp: AuthHttp, private auth: AuthService) {\n    platform.ready().then(() =&gt; {\n\n      \/\/ When the app starts up, there might be a valid\n      \/\/ token in local storage. If there is, we should\n      \/\/ schedule an initial token refresh for when the\n      \/\/ token expires\n      this.auth.startupTokenRefresh();\n\n    });\n  }\n}\n<\/code><\/pre>\n<h2>Wrapping Up<\/h2>\n<p>Awesome, we&#8217;ve successfully implemented authentication in an Ionic 2 app without a whole lot of effort! It can be difficult to code modern authentication features from scratch but, as we&#8217;ve seen, Auth0 does this hard work for us. We&#8217;ve really only scratched the surface too. Auth0 has a lot more to offer, including integration with enterprise systems such as <a href=\"https:\/\/auth0.com\/docs\/saml-configuration\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">SAML<\/a>, <a href=\"https:\/\/auth0.com\/docs\/connections\/enterprise\/active-directory\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">Active Directory<\/a>, and others. To find out more about integrating Auth0 in your app, visit the <a href=\"https:\/\/auth0.com\/docs\/?utm_source=ionicframework&amp;utm_medium=post&amp;utm_campaign=auth0-ionic2\">docs page<\/a> or <a href=\"mailto:support@auth0.com\">drop us a line<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR: Implementing modern authentication and identity can be tricky. Fortunately, Auth0 makes it really easy to get up and running quickly and without any friction. With Auth0 you can use any social identity provider and have features like multifactor authentication, single sign-on, and more, all at the flip of a switch. In this tutorial we&#8217;ll [&hellip;]<\/p>\n","protected":false},"author":27,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[3,13],"class_list":["post-823","post","type-post","status-publish","format-standard","hentry","category-all","tag-ionic","tag-ionic-2"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Ionic 2 and Auth0 - Ionic Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ionic 2 and Auth0\" \/>\n<meta property=\"og:description\" content=\"TL;DR: Implementing modern authentication and identity can be tricky. Fortunately, Auth0 makes it really easy to get up and running quickly and without any friction. With Auth0 you can use any social identity provider and have features like multifactor authentication, single sign-on, and more, all at the flip of a switch. In this tutorial we&#8217;ll [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-03-01T18:54:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-04-14T20:24:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\" \/>\n<meta name=\"author\" content=\"Ryan Chenkie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ryanchenkie\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ryan Chenkie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\"},\"author\":{\"name\":\"Ryan Chenkie\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/64a175c6caa835abd35defa3b0caee19\"},\"headline\":\"Ionic 2 and Auth0\",\"datePublished\":\"2016-03-01T18:54:00+00:00\",\"dateModified\":\"2016-04-14T20:24:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\"},\"wordCount\":1551,\"commentCount\":40,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\",\"keywords\":[\"Ionic\",\"Ionic 2\"],\"articleSection\":[\"All\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\",\"url\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\",\"name\":\"Ionic 2 and Auth0 - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\",\"datePublished\":\"2016-03-01T18:54:00+00:00\",\"dateModified\":\"2016-04-14T20:24:47+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage\",\"url\":\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\",\"contentUrl\":\"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ionic 2 and Auth0\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/64a175c6caa835abd35defa3b0caee19\",\"name\":\"Ryan Chenkie\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cd7b4c36ce84b4c74605abfea78e86636ed2c3a522dcd15b90899409d5f59bac?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cd7b4c36ce84b4c74605abfea78e86636ed2c3a522dcd15b90899409d5f59bac?s=96&d=mm&r=g\",\"caption\":\"Ryan Chenkie\"},\"sameAs\":[\"https:\/\/x.com\/ryanchenkie\"],\"url\":\"https:\/\/ionic.io\/blog\/author\/ryan-chenkie\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ionic 2 and Auth0 - Ionic Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0","og_locale":"en_US","og_type":"article","og_title":"Ionic 2 and Auth0","og_description":"TL;DR: Implementing modern authentication and identity can be tricky. Fortunately, Auth0 makes it really easy to get up and running quickly and without any friction. With Auth0 you can use any social identity provider and have features like multifactor authentication, single sign-on, and more, all at the flip of a switch. In this tutorial we&#8217;ll [&hellip;]","og_url":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0","og_site_name":"Ionic Blog","article_published_time":"2016-03-01T18:54:00+00:00","article_modified_time":"2016-04-14T20:24:47+00:00","og_image":[{"url":"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png"}],"author":"Ryan Chenkie","twitter_card":"summary_large_image","twitter_creator":"@ryanchenkie","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Ryan Chenkie","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0"},"author":{"name":"Ryan Chenkie","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/64a175c6caa835abd35defa3b0caee19"},"headline":"Ionic 2 and Auth0","datePublished":"2016-03-01T18:54:00+00:00","dateModified":"2016-04-14T20:24:47+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0"},"wordCount":1551,"commentCount":40,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage"},"thumbnailUrl":"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png","keywords":["Ionic","Ionic 2"],"articleSection":["All"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/ionic-2-and-auth0#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0","url":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0","name":"Ionic 2 and Auth0 - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage"},"thumbnailUrl":"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png","datePublished":"2016-03-01T18:54:00+00:00","dateModified":"2016-04-14T20:24:47+00:00","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/ionic-2-and-auth0"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#primaryimage","url":"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png","contentUrl":"https:\/\/cdn.auth0.com\/blog\/ionic2-auth\/ionic2-auth-5.png"},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/ionic-2-and-auth0#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Ionic 2 and Auth0"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/64a175c6caa835abd35defa3b0caee19","name":"Ryan Chenkie","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cd7b4c36ce84b4c74605abfea78e86636ed2c3a522dcd15b90899409d5f59bac?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cd7b4c36ce84b4c74605abfea78e86636ed2c3a522dcd15b90899409d5f59bac?s=96&d=mm&r=g","caption":"Ryan Chenkie"},"sameAs":["https:\/\/x.com\/ryanchenkie"],"url":"https:\/\/ionic.io\/blog\/author\/ryan-chenkie"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/27"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=823"}],"version-history":[{"count":0,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/823\/revisions"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}