Authentication
and
Authorization
in
Angular
Objectives
-
Review classical authentication flow
-
Solidify distinction between tokens and cookies
-
Use angular packages to send secure/authorized information using JWT
-
Create the feeling of a "session" without cookies
Classical Authentication
Client
Server
1. Client sends user/password
Classical Authentication
Client
Server
1. Client sends user/password
2. Server validates user/pass and upon success creates a cookie
Classical Authentication
Client
Server
1. Client sends user/password
2. Server validates user/pass and upon success creates a signed cookie
3. Server sends cookie
Classical Authentication
Client
Server
1. Client sends user/password
2. Server validates user/pass and upon success creates a signed cookie
3. Server sends cookie
4.
All further communication
involves the signed cookie
Classical Authentication
Client
Server
1. Client sends user/password
2. Server validates user/pass and upon success creates a signed cookie
3. Server sends cookie
4.
All further requests
send the signed cookie
5.
All further requests check the cookie
Token Authentication
Client
Server
1. Client sends user/password
2. Server validates user/pass and upon success creates a JWT (which are signed)
3. Server sends JWT
4.
All further requests
send the JWT
5.
All further requests check the JWT
Those Look The Same
- Established best practices for securing information have not changed much even since paper based cryptography.
- What has changed is the mechanism for keeping the secret.
- JWTs and Cookies are different standards that behave differently in implementation, but similarly in concept.
So What Matters?
Crucially: a client needs to be able to hold information that uniquely identifies it, but that could not be recreated by a 3rd party attacker.
Then why change?
JWT was invented specifically to deal with cases where cookies do not work well.
Single Page App + Service Oriented Architecture is an example of such a case.
Implementation
- Interceptors on the front end
- login + Middleware on the back end
- Joy
"Interceptors": Request
Interceptors are the middleware of angular.
Angular Client:
Initial HTTP
Request
Interceptor
Server
"Interceptors": Response
Interceptors are the middleware of angular.
Angular Client:
Initial HTTP
Request
Interceptor
Server
"Interceptors": The Code
app.config(function($routeProvider, $httpProvider){
$httpProvider.interceptors.push('testInterceptor');
})
Step 1: register your interceptor with $httpProvider
This is a service that we are about to create
"Interceptors": The Code
.service('testInterceptor', function testInterceptor(){
return {
request: function(config){
return config;
},
requestError: function(err){
return err;
},
response: function(response){
return response;
},
responseError: function(err){
return err;
}
};
})
Step 2: Create the "interceptor service"
"Interceptors": The Code
myApp.service('testInterceptor', function testInterceptor(){
return {
// An interceptor that is called when making
// a request. The config object is the same
// type of object used when calling $http(config)
request: function(config){
return config;
}
};
})
Step 2.5: Types
Request interceptor
"Interceptors": The Code
myApp.service('testInterceptor', function testInterceptor(){
return {
// An interceptor that runs when $http
// or another interceptor encounters an
// error. The input is that error.
requestError: function(err){
return err;
}
};
})
Step 2.5: What are these?
Request Error interceptor
"Interceptors": The Code
myApp.service('testInterceptor', function testInterceptor(){
return {
// An interceptor that runs when a
// response is received. The parameter
// here is the data from that response.
response: function(response){
return response;
}
};
})
Step 2.5: What are these?
Response Interceptor
"Interceptors": The Code
myApp.service('testInterceptor', function testInterceptor(){
return {
// An interceptor that runs when
// an error occurs during another
// interceptor. *NOT* if the response
// object itself is erroneous (404/500)
responseError: function(err){
return err;
}
};
})
Step 2.5: What are these?
Response Error Interceptor
"Interceptors": The Code
// Somewhere in the login code:
var loginPromise = $http({
method: "POST",
url: "/login",
data: {user: "teb", password: "123456"}
});
loginPromise.then(function(response) {
// Assuming this is how your server responds
if(response.data.jwt) {
localStorage.set('token', response.data.jwt);
}
});
Step 3: If you login successfully -- store JWT
"Interceptors": The Code
myApp.service('testInterceptor', function testInterceptor(){
return {
request: function(config){
var token = localStorage.getItem("token");
if(token) {
config.headers.Authorization = "Bearer " + token;
}
return config;
}
};
})
Step 4: Use an Interceptor for JWT tokens
Ask local storage if there is a JWT -- if there is then always throw it in the authorization header
Questions?
Questions for you
SURPRISE
Get a whiteboard, and draw the steps for JWT authorization. Explain it to your neighbor!
AuthenticationAuthorizationAngular
By Tyler Bettilyon
AuthenticationAuthorizationAngular
- 1,273