Good, easy to understand JSON web token (JWT) usage example, which does not contain much unrelated stuff:
https://github.com/auth0/angular-token-auth
Article with explanation:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
Listings just in case if it suddenly disappear:
auth.server.js
auth.client.js
index.html
package.json
https://github.com/auth0/angular-token-auth
Article with explanation:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
Listings just in case if it suddenly disappear:
auth.server.js
var express = require('express');
var bodyParser = require('body-parser');
var jwt = require('jsonwebtoken'); //https://npmjs.org/package/node-jsonwebtoken
var expressJwt = require('express-jwt'); //https://npmjs.org/package/express-jwt
var secret = 'this is the secret secret secret 12356';
var app = express();
// We are going to protect /api routes with JWT
app.use('/api', expressJwt({secret: secret}));
app.use(bodyParser.json());
app.use('/', express.static(__dirname + '/'));
app.use(function(err, req, res, next){
if (err.constructor.name === 'UnauthorizedError') {
res.status(401).send('Unauthorized');
}
});
app.post('/authenticate', function (req, res) {
//TODO validate req.body.username and req.body.password
//if is invalid, return 401
if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
res.status(401).send('Wrong user or password');
return;
}
var profile = {
first_name: 'John',
last_name: 'Doe',
email: 'john@doe.com',
id: 123
};
// We are sending the profile inside the token
var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });
res.json({ token: token });
});
app.get('/api/restricted', function (req, res) {
console.log('user ' + req.user.email + ' is calling /api/restricted');
res.json({
name: 'foo'
});
});
app.listen(8080, function () {
console.log('listening on http://localhost:8080');
});
auth.client.js
var myApp = angular.module('myApp', []);
//this is used to parse the profile
function url_base64_decode(str) {
var output = str.replace('-', '+').replace('_', '/');
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw 'Illegal base64url string!';
}
return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
}
myApp.controller('UserCtrl', function ($scope, $http, $window) {
$scope.user = {username: 'john.doe', password: 'foobar'};
$scope.isAuthenticated = false;
$scope.welcome = '';
$scope.message = '';
$scope.submit = function () {
$http
.post('/authenticate', $scope.user)
.success(function (data, status, headers, config) {
$window.sessionStorage.token = data.token;
$scope.isAuthenticated = true;
var encodedProfile = data.token.split('.')[1];
var profile = JSON.parse(url_base64_decode(encodedProfile));
$scope.welcome = 'Welcome ' + profile.first_name + ' ' + profile.last_name;
})
.error(function (data, status, headers, config) {
// Erase the token if the user fails to log in
delete $window.sessionStorage.token;
$scope.isAuthenticated = false;
// Handle login errors here
$scope.error = 'Error: Invalid user or password';
$scope.welcome = '';
});
};
$scope.logout = function () {
$scope.welcome = '';
$scope.message = '';
$scope.isAuthenticated = false;
delete $window.sessionStorage.token;
};
$scope.callRestricted = function () {
$http({url: '/api/restricted', method: 'GET'})
.success(function (data, status, headers, config) {
$scope.message = $scope.message + ' ' + data.name; // Should log 'foo'
})
.error(function (data, status, headers, config) {
alert(data);
});
};
});
myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
responseError: function (rejection) {
if (rejection.status === 401) {
// handle the case where the user is not authenticated
}
return $q.reject(rejection);
}
};
});
myApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Angular Authentication</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
<script src="./auth.client.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="UserCtrl">
<span ng-show="isAuthenticated">{{welcome}}</span>
<form ng-show="!isAuthenticated" ng-submit="submit()">
<input ng-model="user.username" type="text" name="user" placeholder="Username" />
<input ng-model="user.password" type="password" name="pass" placeholder="Password" />
<input type="submit" value="Login" />
</form>
<div>{{error}}</div>
<div ng-show="isAuthenticated">
<a ng-click="callRestricted()" href="">Shh, this is private!</a>
<br>
<div>{{message}}</div>
<a ng-click="logout()" href="">Logout</a>
</div>
</div>
</body>
</html>
package.json
{
"name": "angular-token-auth",
"version": "0.1.0",
"dependencies": {
"body-parser": "^1.9.0",
"express": "~4.9.0",
"express-jwt": "~0.2.1",
"jsonwebtoken": "~0.4.0"
},
"description": "Example of Token-based authentication in [AngularJS](http://angularjs.org) with [Express](http://expressjs.com).",
"main": "auth.server.js",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/auth0/angular-token-auth.git"
},
"keywords": [
"angular",
"auth",
"jwt",
"express"
],
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/auth0/angular-token-auth/issues"
},
"homepage": "https://github.com/auth0/angular-token-auth"
}