Thursday, 10 November 2016

Authenticate your Firebase users with LINE Login

Khanh LeViet
Developer Advocate

Nowadays, many users prefer using federated login, such as Google Sign-In, Facebook, Twitter and others, over having to create a new account for every service they use. Each user has their own favorite federated login provider, and it would take a lot of effort to integrate and manage each federated login provider for your app. This is where Firebase Authentication can help.

Firebase Authentication supports many popular federated login providers. You just need to integrate with Firebase Authentication, and let Firebase automatically manage multiple federated login providers under the hood for you.

However, depending on where your users are in the world, they may prefer a federated login providers for which Firebase does not have built-in support yet. For example, in Japan and many Asian countries, LINE Login is very popular with hundreds of millions of users, so you may want to support it as well. Fortunately, it is fairly simple to integrate LINE Login, as well as many other federated login, with Firebase Authentication using Custom Auth.

In one of our previous blog post, we have shown how to support federated login that was not available out-of-the-box with Firebase Authentication on the web using our JavaScript SDK. In this blog post, I will show you how to integrate with LINE Login on iOS and Android.

Design Overview


Here is how the login flow looks like:

Step 1: Use LINE Login SDK to log user in, and acquire their LINE Access Token

Step 2:Send their LINE Access Token to your server and validate it with LINE authentication server. If the token is valid, then create a Firebase Custom Auth token correspond to the user, and send it back to user's device.

Step 3:Use the Firebase Custom Auth token to login to Firebase from the device.

Let's Build It!

Preparation

You will need to do some setup work to get your LINE business account and Firebase project ready.

  • Follow the steps here to setup your LINE business account, and integrate LINE SDK to your app
  • Next, make sure that you have added Firebase Authentication library to your app (iOS / Android)
  • You may want to use our Firebase Server SDK to generate Custom Auth token, but that is optional because any JSON Web Token library can do the work as well.

Start the LINE Login flow

Refer to LINE Login document (iOS / Android) to integrate LINE SDK to your app and implement LINE Login flow. Once user has successfully logged in, you can get their LINE access token as below:

iOS (Objective-C)

NSString *lineAccessToken = self.lineAdapter.getLineApiClient.accessToken;

Android

LineAuthManager authManager = LineSdkContextManager.getSdkContext().getAuthManager();
final String accessToken = authManager.getAccessToken().accessToken;

Then you can use your favorite networking library to send the access token to your own server for validation. In this sample code, I use GTM HTTP Fetcher for iOS and Volley for Android.

iOS (Objective-C)

NSURL *url = [NSURL URLWithString:@"https:///verifyToken"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"content-type"];

NSDictionary *token = @{@"token" : lineAccessToken};
NSError *error;
NSData *requestBody = [NSJSONSerialization dataWithJSONObject:token
options:kNilOptions error:&error];
[request setHTTPBody:requestBody];
GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
if (!error) {
// Extract Firebase Custom Auth token from response
// ・・・
}
}];

Android

HashMap validationObject = new HashMap<>();
validationObject.put("token", accessToken);
Response.Listener responseListener = new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
// Extract Firebase Custom Auth token from response
// ・・・
}
};
JsonObjectRequest fbTokenRequest = new JsonObjectRequest(
Request.Method.POST,
"https:///verifyToken",
new JSONObject(validationObject),
responseListener, errorListener);

NetworkSingleton.getInstance(activity).addToRequestQueue(fbTokenRequest);

Exchange LINE Access Token for Firebase Custom Auth Token

You will need a server to validate LINE access token and generate a corresponding Firebase Custom Auth token for that user. You can build a simple one with Firebase Node.js Server SDK and Express web server.

Firstly, your server receives the LINE Access Token from user's device and validates it using LINE Social Rest API. Don't forget to verify the channelId value in API response to make sure that the access token is actually issued for your app. This is to prevent spoof attack, of which attackers reuse access token from other app/channel to attempt login to your app.

Server (Node.js)

app.post('/verifyToken', (req, res) => {
if (!req.body.token) {
return res.status(400).send('Access Token not found');
}
const reqToken = req.body.token;

// Send request to LINE server for access token verification
const options = {
url: 'https://api.line.me/v1/oauth/verify',
headers: {
'Authorization': `Bearer ${reqToken}`
}
};
request(options, (error, response, body) => {
if (!error && response.statusCode === 200) {
const lineObj = JSON.parse(body);
// Don't forget to verify the token's channelId to prevent spoof attack
if ((typeof lineObj.mid !== 'undefined')
&& (lineObj.channelId === myLINEChannelId)) {
// Access Token Validation succeed with LINE server
// Generate Firebase token and return to device
const firebaseToken = generateFirebaseToken(lineObj.mid);

// Update Firebase user profile with LINE profile
updateUserProfile(reqToken, firebaseToken, lineObj.mid, () => {
const ret = {
firebase_token: firebaseToken
};
return res.status(200).send(ret);
});
}
}

const ret = {
error_message: 'Authentication error: Cannot verify access token.'
};
return res.status(403).send(ret);

});

}
});

After successfully validated LINE Access Token, use Firebase Server SDK to generate Firebase Custom Auth token and return it to the user device. You can reuse LINE's user ID for your Firebase user ID.

Server (Node.js)

function generateFirebaseToken(lineMid) {
var firebaseUid = 'line:' + lineMid;
var additionalClaims = {
provider: 'LINE'
};
return firebase.auth().createCustomToken(firebaseUid);
}

We also have a Firebase Server Java SDK.

You can make use of solutions like App Engine Flexible Environment or Cloud Functions to free yourself from managing the server.

Login to Firebase using Custom Auth token

After receiving the Firebase Custom Auth token, just use it to sign the user in Firebase:

iOS (Objective-C)

[[FIRAuth auth] signInWithCustomToken:firebaseToken 
completion:^(FIRUser * _Nullable user, NSError * _Nullable error) {
// Process sign in result
// ・・・
}];

Android

FirebaseAuth.getInstance()
.signInWithCustomToken(firebaseToken)
.addOnCompleteListener(new OnCompleteListener() {
// Process sign in result
// ・・・
});

Try it out!

Our sample code is open source. Feel free to download and give it a try. https://github.com/firebase/custom-auth-samples/tree/master/Line

Share:

Wednesday, 9 November 2016

Get up and running on Firebase this weekend with Firebase in a Weekend

Shanea King-Roberson
Google Developer Training

Earlier this year, we introduced the expansion of Firebase: a unified app platform that provides developers a variety of tools and a scalable infrastructure to build high quality apps and grow successful businesses across Android, iOS and the Web. This blog post is not about the 'what' but more about the 'how'. How do you implement Firebase into your app quickly and easily?

Today we are launching a complete end-to-end video training course called "Firebase in a Weekend". Whether you develop Android or iOS apps, the training course helps you understand many of the core features of Firebase, learned by building an app from the ground up.



Join some of our favorite Firebase instructors as they walk you through building a functioning messaging app using:

  • Realtime database - Data is synchronized across all clients in realtime, and remains available when your app goes offline.
  • Auth and FirebaseUI Auth Library - Get users logged into your app quickly and protect their data.
  • Notifications - Lets you easily deliver notifications to your users without writing a line of code.
  • Remote Config - Gives you a collection of variables that you can change from the Firebase console in order to tune and customize your app on the fly to deliver the best experience to your users.
  • Analytics - Set up analytics to gather data the moment you publish.

We partnered with Udacity, the online learning platform, to give you a more personalized, in depth explanation of Firebase and its features. You can learn how to do it on either Android or iOS by watching short videos enhanced with code samples and assessments.

Check out the Android or iOS course online for no charge. Check out all of the courses at udacity.com/google.

Share:

Bringing Firebase To Your Server

Jacob Wenger
Software Engineer

With Firebase, we've been working towards a world where developers don't have to deal with managing servers and can instead build web and mobile apps with only client-side code. However, there are times when you really do need to spin up your own server. For example, you may want to integrate with a third-party API (such as an email or SMS service), complete a computationally expensive task, or have a need for a trusted actor. We want to make your experience on this part of your stack as simple as it is on the front-end. Towards that aim, we announced the Firebase Admin SDKs for Node.js and Java at the Firebase Dev Summit in Berlin earlier this week.

What are the Admin SDKs?

The Firebase Admin SDKs provide developers with programmatic, second-party access to Firebase services from server environments. Second-party here refers to the fact that the SDKs are granted elevated permissions that allow them to do more than a normal, untrusted client device can. The Admin SDKs get these elevated permissions since they are authenticated with a service account, a special Google account that can be used by applications to access Google services programmatically. The Admin SDKs are meant to complement the existing Firebase web and mobile clients which provide third-party, end-user access to Firebase services on client devices.

Some of this may sound familiar for those of you who have used the existing Firebase Node.js and Java SDKs. The difference is that we have now split the second-party (aka "admin") and third-party (aka "end-user") access use cases into separate SDKs instead of conflating them together. This should make it easier for beginners and experts alike to know which SDK to use and which documentation to follow. It also allows us to tailor the Admin SDKs towards server-specific use cases. A great example of this is the new user management auth API which we will go into in the next section.

What can the Admin SDKs do?

The Admin SDKs for Node.js and Java offer the following admin capabilities that already existed in the prior server SDKs:

In addition, the Node.js SDK brings some exciting new functionality:

  • Admin API for managing Firebase Auth users, including the ability to fetch user data, create new users, update user properties, and delete users. You can do all of this without a user's existing password and without worrying about rate limiting. This has been a heavily requested feature from developers for years now and we are excited to finally put it into your hands.
  • Auto-discovery of service account credentials on Google infrastructure like Google App Engine and Google Compute Engine. This means you don't need to manage service account credentials yourself. Instead, you can make use of Google Application Default Credentials to run the same exact code on your local, staging, and production environments, no configuration required.

How can I get started with the Admin SDKs?

The best place to start is with our Admin SDKs setup guide. The guide will walk you through how to download the SDK, generate a service account key file, and use that key file to initialize the Admin SDK. Thanks to our new Service Accounts panel in your Firebase Console settings, generating service account keys should be a breeze.

What's next for the Admin SDKs?

This is really just the beginning for the Admin SDKs. We plan to expand the Admin SDKs across two dimensions. Firstly, we want to provide Admin SDKs in more programming languages, allowing you to write code in the language you feel most comfortable. Secondly, we plan to integrate with more Firebase services, including adding support for services like Firebase Cloud Messaging and bringing the new user management API to Java.

Would you like us to build an Admin SDK in a particular language? Do you want the Admin SDKs to support a certain Firebase service or feature? Let us know in the comments below or by sending us a note through our feature request support channel.

We are excited to expand our first-class support for backend developers in the Firebase ecosystem. Stay tuned for more to come in the future!

Share:

Monday, 7 November 2016

Live from the Firebase Dev Summit in Berlin: Firebase, six months after I/O

Francis Ma
Francis Ma
Firebase Product Manager

Our goal with Firebase is to help developers build better apps and grow them into successful businesses. Six months ago at Google I/O, we took our well-loved backend-as-a-service (BaaS) and expanded it to 15 features to make it Google’s unified app development platform, available across iOS, Android, and the web.

We launched many new features at Google I/O, but our work didn’t stop there. Since then, we’ve learned a lot from you (750,000+ projects created on Firebase to date!) about how you’re using our platform and how we can improve it. Thanks to your feedback, today we’re launching a number of enhancements to Crash Reporting, Analytics, support for game developers and more. For more information on our announcements, tune in to the livestream video from Firebase Dev Summit in Berlin. They’re also listed here:

Improve App Quality to Deliver Better User Experiences

Firebase Crash Reporting comes out of Beta and adds a new feature that helps you diagnose and reproduce app crashes.

Often the hardest part about fixing an issue is reproducing it, so we’ve added rich context to each crash to make the process simple. Firebase Crash Reporting now shows Firebase Analytics event data in the logs for each crash. This gives you clarity into the state of your app leading up to an error. Things like which screens of your app were visited are automatically logged with no instrumentation code required. Crash logs will also display any custom events and parameters you explicitly log using Firebase Analytics. Firebase Crash Reporting works for both iOS and Android apps.

Glide, a popular live video messaging app, relies on Firebase Crash Reporting to ensure user quality and release agility. “No matter how much effort you put into testing, it will never be as thorough as millions of active users in different locations, experiencing a variety of network conditions and real life situations. Firebase allows us to rapidly gain trust in our new version during phased release, as well as accelerate the process of identifying core issues and providing quick solutions.” - Roi Ginat, Founder, Glide.

Firebase Test Lab for Android supports more devices and introduces a free tier.

We want to help you deliver high-quality experiences, so testing your app before it goes into the wild is incredibly important. Firebase Test Lab allows you to easily test your app on many physical and virtual devices in the cloud, without writing a single line of test code. Beginning today, developers on the Spark service tier (which is free!) can run five tests per day on physical devices and ten tests per day on virtual devices—with no credit card setup required. We’ve also heard that you want more device options, so we’ve added 11 new popular Android device models to Test Lab, available today.

Illustration of Firebase Crash Reporting

Make Faster Data Driven Decisions with Firebase Analytics

Firebase Analytics now offers live conversion collection, a new integration with Google “Data Studio”, and real-time exporting to BigQuery.

We know that your data is most actionable when you can see and process it as quickly as possible. Therefore, we’re announcing a number of features to help you maximize the potential of your analytics events:

  1. Real-time uploading of conversion events
  2. Real-time exporting to BigQuery
  3. DebugView for validation of your analytics instrumentation is currently offered in limited availability and will be made more broadly available later this year

We were happy to give you a sneak preview at the Firebase Dev Summit of a new feature we are now building, StreamView, which will offer a live, dynamic view of your analytics data as it streams in.

To further enhance your targeting options, we’ve improved the connection between Firebase Analytics and other Firebase features, such as Dynamic Links and Remote Config. For example, you can now use Dynamic Links on your Facebook business page, and we can identify Facebook as a source in Firebase Analytics reporting. Also, you can now target Remote Config changes by User Properties, in addition to Audiences.

Build Better Games using Firebase

Firebase now has a Unity plugin!

Game developers are building great apps, and we want Firebase to work for you, too. We’ve built an entirely new plugin for Unity that supports Analytics, the Realtime Database, Authentication, Dynamic Links, Remote Config, Notifications and more. We've also expanded our C++ SDK with Realtime Database support.

Integrate Firebase Even Easier with Open-Sourced UI Library

FirebaseUI is updated to v1.0.

FirebaseUI is a library that provides common UI elements when building apps, and it’s a quick way to integrate with Firebase. FirebaseUI 1.0 includes a drop-in UI flow for Firebase Authentication, with common identity providers such as Google, Facebook, and Twitter. FirebaseUI 1.0 also added features such as client-side joins and intersections for the Realtime Database, plus integrations with Glide and SDWebImage that make downloading and displaying images from Firebase Storage a cinch. Follow our progress or contribute to our Android, iOS, and Web components on Github.

Learn More via Udacity and Join the Firebase Community

We want to provide the best tool for developers, but it’s also important that we give resources and training to help you get more out of the platform. As such, we’ve created a new Udacity course: Firebase in a Weekend! It’s an instructor-led video course to help all developers get up and running with Firebase on iOS and Android, in two days.

Finally, to help wrap your head around all our announcements, we’ve created a new demo app. This is an easy way to see how Analytics, Crash Reporting, Test Lab, Notifications, and Remote Config work in a live environment, without having to write a line of code.

Helping developers build better apps and successful businesses is at the core of Firebase. We work hard on it every day. We love hearing your feedback and ideas for new features and improvements—and we hope you can see from the length of this post that we take them to heart! Follow us on Twitter, join our Slack channel, participate in our Google Group, and let us know what you think. We’re excited to see what you’ll build next!

Share:

Thursday, 3 November 2016

Pirate Metrics: Retain More Users With Firebase

Parul Soi
Parul Soi
Developer Relations Program Manager

In the past three posts, I've introduced readers to Pirate Metrics, and shown how you can boost your acquisition strategy and activation numbers with Firebase products.

In this post, we're going to talk about one of the biggest problems majority of apps face: retention. The hard truth is that most people tend to only use a few applications every week, abandoning a majority of them after just a few tries. This might happen even if you did successfully activate a user.

The goal, for any product, is to become a habit for their users. And, for a person to pick up new habits, they need the help of triggers. The best products carefully use external triggers — things like push notifications, E-mailers — at appropriate times which help building habits.

For years, we have offered powerful tools to help you build these experiences: Google Cloud Messaging. Cloud Messaging is now a part of the Firebase suite of SDKs, becoming even more powerful than before.

The key capability added, thanks to this change, is something we call Firebase Notifications. By simply adding the required dependency to your application, you can now send push notifications to your users straight from the Firebase console. But that's not all: you can target the notification to a required segment. For example, you can inform those users who have shown an interest in a particular product that you have a deal running in your E-commerce application.

While quite useful, particularly considering how little you need to do to add them to your app, sending Push Notifications is a manual process and best utilized for campaigns. To truly improve your product, you need to first understand when you tend to lose your users, and build a system that helps you retain them.

The first part can be solved using the cohorts from Firebase Analytics. Cohorts help you visualise your retention by showing you what percentage of users do you retain over a period of time, broken down by days or weeks. Most of your users are typically lost in the first couple of days, which is usually an issue with your activation strategy. However, this decline tends to flatten out.

While you should certainly work on your activation strategy to help improve your cohort numbers on the first couple of days, you also want to look at some way to improve the numbers a little later, such as around days 5-7. One fairly straightforward solution is to build an automated system that sends push notifications using Firebase Cloud Messaging to these users approximately a week after they sign up. Using some kind of flag for "last used time", you could also ensure this notification is only shown to those users who are at risk of being dropped off.

You could utilize this strategy for things like extending trial periods for users who haven't used your product enough, giving yourself an extended opportunity to convert them into paying customers. Deals of any other form (either for E-commerce products or for in-app products) are other ways.

A carefully crafted strategy could play a critical role in your overall business. Do be mindful of avoiding a spammy notification system: you'll probably annoy your users and increase your uninstall count.

There are additional possibilities as well. Firebase Analytics tracks uninstalled users for you using the automated event "app_remove". As mentioned in the second post on acquisition, you can create an audience for users who have fired this event and retarget them using Adwords.

Also, using Firebase App Indexing in your application would help highlight content from your service in Google search results for your users. This is particularly useful during the early phases of the user's time with you when they haven't quite developed a habit of using your application directly.

Share:

Wednesday, 2 November 2016

Easy Angular Authentication with JSON Web Tokens

Easy Angular Authentication with JSON Web Tokens

Stateless authentication is a great fit for Angular apps. In this post, guest-blogger Ryan Chenkie from Auth0 talks about implementing it using JSON Web Tokens. -- Victor Savkin


TL;DR: Single page apps--like the ones we build with Angular--present a few challenges when it comes to authentication. In general, traditional session-based authentication isn't a good fit for SPAs that use data APIs because it necessitates state on the server. A better way to do authentication in Angular apps (and SPAs in general) is with JSON Web Tokens (JWTs). Read on to find out more about JWTs, or check out Angular 2 Tour of Secret Heroes to see an example of a full Angular 2 app with user authentication.
Pretty well all non-trivial applications require some way of dealing with user authentication and authorization. This can be fairly straight-forward in round-trip applications because all that is really needed when a user logs in is to check their credentials against a database, save a session for them on the server, and return a cookie to be saved in their browser. The cookie is then sent along in subsequent requests to the server and is checked against the session to verify their identity.
This works well for "traditional" applications, but it isn't a great fit for single page apps that use data APIs. Since SPAs are client-side apps, dealing with the notion of the user's authentication state is also a bit trickier. Essentially what it boils down to is that we need some indication of the user's authentication state even though the backends that we rely on should remain stateless. This isn't a problem in round-trip apps because the HTML and data that get returned to the user is constructed on the backend, which is exactly the place that a stateful check can be done to figure out whether or not the user is currently logged in. When we use REST APIs for data however, a stateful session that tracks authentication is bad practice.

JSON Web Tokens - Stateless Authentication in Angular Apps

A great way to do stateless authentication in an Angular app is to use JSON Web Tokens (JWT). JWT is an open standard (RFC 7519), and likely the most compelling reason to choose it as an authentication mechanism is that it can be used to transmit arbitrary data as a JSON object. Since JWTs are digitally signed with a secret key that lives only on the server, we can rest assured that the information in the token can't be tampered with at any point. If the payload in the JWT were to be tampered with, the token would become invalid, which means it wouldn't be able to get past any checkpoints on the server. This makes JWT the perfect mechanism for transmitting information about a user and it gives us a distinct advantage: we can include everything required for our API to know who the user is and what level of access they should have, and the API doesn't need to know a single thing about them prior to the JWT arriving.
So what does a JWT look like? Here's an example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWTs contain three parts, and each of them is tacked together with a dot separator. The three parts are:

Header

Where we define the algorithm used to sign the token, as well as the token type.

Payload

The meat of the JWT. This is where we keep a JSON object of all the claims we want. Claims can include those that are registered in the JWT spec, as well as any arbitrary data we want.

Signature

The signature is where the signing action happens. To get the signature, we take the Base64URL encoded header, tack the Base64URL encoded payload next to it, and run that string along with the secret key through the hashing algorithm we've chosen. For the token to properly decode on the backend, it needs to have exactly this form, which means that if someone tries to change any of the information contained within, they'll be out of luck.
We can see this token decoded with Auth0's open source JWT debugger.
angular jwt authentication
It should be noted that although JWTs are digitally signed, they are not encrypted. While the digital signature ensures that the content of a JWT cannot be tampered with, they should not be used to transmit sensitive information, as the payload can easily be decoded with tools like the jwt.io debugger.

How Are JWTs Used to Authenticate Angular Apps?

For Angular apps that use data APIs, the typical scenario is this:
  1. Users send their credentials to the server which are verified against a database. If everything checks out, a JWT is sent back to them.
  2. The JWT is saved in the user's browser somehow--either by holding it in local storage or in a cookie.
  3. The presence of a JWT saved in the browser is used as an indicator that a user is currently logged in.
  4. The JWT's expiry time is continually checked to maintain an "authenticated" state in the Angular app, and the user's details are read from the payload to populate views such as the their profile.
  5. Access to protected client-side routes (such as the profile area) are limited to only authenticated users
  6. When the user makes XHR requests to the API for protected resources, the JWT gets sent as an Authorization header using the Bearer scheme, or as a cookie.
  7. Middleware on the server--which is configured with the app's secret key--checks the incoming JWT for validity and, if valid, returns the requested resources.
Fortunately for us, there are several open source libraries for both Angular 1.x and 2 which help us work with JWTs. These libraries are varied in their functionality, but some of the features we get with them are the ability to:
  • Decode the JWT and read its payload
  • Attach the JWT as an Authorization header to XHR requests
  • Have a service which exposes methods for logging in and logging out, and which checks whether the current user's JWT is expired or not

Angular 1.x

Angular 2

There are also hosted authentication solutions that can drastically simplify the process of setting up user login and signup functionality for Angular apps. This basically means that we don't need to worry about any logic for checking the user's credentials and signing tokens for them.

Authentication in Action

So we've got a list of things that our Angular apps should be doing to deal with authentication, but what does this look like in practice? Let's see an example using Angular 2.

Retrieve a JWT for a User and Save it in Local Storage

To retrieve a JWT for a user, we need to verify their credentials against a database. If everything checks out, we sign a JWT and send it back to them in the response. We can use almost any server-side language or framework for this task, and there are JWT libraries available for almost everything.
With the token signing logic set up, we need to expose an endpoint that the app can make a request to for authentication. For this, we just need to send a regular HTTP request. Placing this logic in an injectable service gives us a way to reuse it across our application.
// auth.service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class AuthService {

constructor(private http: Http) {}

login(credentials) {
this.http.post('https://my-app.com/api/authenticate', credentials)
.map(res => res.json())
.subscribe(
// We're assuming the response will be an object
// with the JWT on an id_token key
data => localStorage.setItem('id_token', data.id_token),
error => console.log(error)
);
}
}
We can then wire up a form which takes input from the user and calls the AuthService.
// login.component.ts

import { Component } from '@angular/core';
import { AuthService } from './auth.service';

interface Credentials {
username: string,
password: string
}

@Component({
selector: 'login',
template: `
<form #f="ngForm" (ngSubmit)="onLogin(f.value)" *ngIf="!auth.loggedIn()">
<input type="text" placeholder="username" ngControl="username">
<input type="password" placeholder="password" ngControl="password">
<button type="submit">Submit</button>
</form>
`
})

export class LoginComponent {

credentials: Credentials;

constructor(private auth: AuthService) {}

onLogin(credentials) {
this.auth.login(credentials);
}
}
With the login form and the authentication service in place, the user's JWT will be saved in local storage if they successfully authenticate.
You can see that we've got an *ngIf condition on the form which is looking for a loggedIn method on the AuthService. Let's put that in next.

Checking for an Unexpired Token

With stateless authentication, the only real indication for the front end that the user is "authenticated" is if they have an unexpired JWT. Certainly a more robust indication would be a check to make sure their JWT is not only unexpired, but is also still valid. However, to do this kind of check, the front end would need to know the secret key used to sign the JWT, and we really don't want to expose that. Simply checking the expiry is just fine though; if the token is invalid (in other ways than it just being expired), it won't be useful for retrieving protected API resources anyway.
To do this kind of check, we can get some help from angular2-jwt's tokenNotExpired function.
npm install angular2-jwt
// auth.service.ts

import { tokenNotExpired } from 'angular2-jwt';

...

loggedIn() {
return tokenNotExpired();
}

...
This function simply checks the expiry date of the JWT and returns true if it is not expired.

Limit Routes to Authenticated Users

We've got a way to hide our links and navigation elements if the user either doesn't have a JWT or if their JWT is expired. However, they could still navigate by plugging in URI segments manually, so what we need is a way to limit navigation to private routes altogether. To do this we can set up an AuthGuard which checks whether the user has an unexpired JWT in local storage. We'll then apply the guard through CanActivate when we set up the routing configuration.
// auth-guard.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { CanActivate } from '@angular/router';
import { Auth } from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private auth: Auth, private router: Router) {}

canActivate() {
if(this.auth.loggedIn()) {
return true;
} else {
this.router.navigateByUrl('/unauthorized');
return false;
}
}
}
When route navigation is requested, AuthGuard will use the AuthService to check for the presence of an unexpired JWT and, if one exists, the user will be allowed to continue to the route. If the user isn't authenticated however, they will be navigated to an "unauthorized" page.
The AuthGuard needs to be applied to whichever routes should be kept private, and this is done in the RouterConfig setup.
...

import { AuthGuard } from './auth-guard.service';

export const routes: RouterConfig = [
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard] },
{ path: 'unauthorized', component: UnauthorizedComponent }
];

...

Send Authenticated HTTP Requests

The last big step for applying authentication to our app is to have the user's JWT sent as an Authorization header in the HTTP requests they make. Since Angular 2 doesn't have any concept of HTTP interceptors like Angular 1.x does, we need to either send the header in the options object of each request, or we can wrap Http to perform this automatically. The angular2-jwt library provides AuthHttp which does the latter.
// secure-stuff.component.ts

import { Component } from '@angular/core';
import { AuthHttp, tokenNotExpired } from 'angular2-jwt';
import 'rxjs/add/operator/map';

@Component({
selector: 'secure-stuff',
template: `
<button (click)="getSecureStuff()">Get Secure Stuff!</button>
`
})

export class SecureStuffComponent {

stuff: [];

constructor(private authHttp: AuthHttp) {}

getSecureStuff() {
this.authHttp.get('https://my-app.com/api/secure-stuff')
.map(res => res.json())
.subscribe(
data => this.stuff = data.stuff,
error => console.log(error)
);
}
}
Note: Any application that uses JWT authentication should always be served over HTTPS to prevent malicious interception of the token.

Log the User Out

With stateless authentication using JWTs, logging the user out is just a matter of removing their token from local storage.
// auth.service.ts

...

@Injectable()
export class AuthService {

...

logout() {
localStorage.removeItem('id_token');
}
}
You might be wondering if this is secure or not, given the fact that we're just removing the token from its holding place and it could, in reality, still be used to access the API. We've got two options to address this concern: we can set the token's expiry time to be short and/or we can implement token blacklisting on the server. With a short window of validity, the JWT can't be exploited for very long, and with blacklisting, the token's ability to access secure resources can be revoked altogether.

Full Example: Angular 2 Tour of Secret Heroes

It would be nice to see all of this authentication business in action in a working app. For that, I've put together a fork of John Papa's Tour of Heroes app (used in the Angular 2 Getting Started guide), called Angular 2 Tour of Secret Heroes. In this app, all the original heroes data--plus a set of new 'secret' heroes--has been moved to an Express server. Authentication happens with Auth0, and angular2-jwt is used for protecting routes, conditionally showing UI elements, and sending authenticated HTTP requests.

Wrapping Up

Stateless authentication has distinct advantages over traditional session-based auth. Keeping our APIs stateless makes them more agile and lets us easily port our apps to other platforms like mobile or desktop. With open source libraries, such as angular2-jwt, we can easily check for token validity and send authenticated HTTP requests with just a bit of configuration.
If you're interested in adding authentication to an Angular 1.x app, the things we went through here still apply, but there are a few differences to keep in mind. For instance, Angular 1.x has HTTP interceptors which can be used to attach the Authorization header to requests, so there's no need to wrap the $http service.
For more on Angular 1.x and 2 authentication, as well as tutorials about Angular in general, be sure to check out the Auth0 blog.
Share: