├── .gitignore
├── .jshintrc
├── package.json
├── index.html
├── README.md
├── LICENSE.txt
├── auth.server.js
└── auth.client.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "esnext": true,
4 | "bitwise": true,
5 | "curly": true,
6 | "eqeqeq": true,
7 | "immed": true,
8 | "indent": 2,
9 | "latedef": true,
10 | "newcap": true,
11 | "noarg": true,
12 | "quotmark": "single",
13 | "regexp": true,
14 | "undef": true,
15 | "strict": false,
16 | "smarttabs": true,
17 | "expr": true,
18 |
19 |
20 | "evil": true,
21 | "browser": true,
22 | "regexdash": true,
23 | "wsh": true,
24 | "trailing": true,
25 | "sub": true,
26 | "unused": true,
27 | "laxcomma": true,
28 |
29 | "globals": {
30 | "after": false,
31 | "before": false,
32 | "afterEach": false,
33 | "beforeEach": false,
34 | "describe": false,
35 | "it": false,
36 | "angular": false,
37 | "Auth0Widget": false,
38 | "Auth0": false
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-token-auth",
3 | "version": "0.1.0",
4 | "dependencies": {
5 | "body-parser": "^1.9.0",
6 | "express": "~4.9.0",
7 | "express-jwt": "~0.2.1",
8 | "jsonwebtoken": "~0.4.0"
9 | },
10 | "description": "Example of Token-based authentication in [AngularJS](http://angularjs.org) with [Express](http://expressjs.com).",
11 | "main": "auth.server.js",
12 | "devDependencies": {},
13 | "scripts": {
14 | "test": "echo \"Error: no test specified\" && exit 1"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/auth0/angular-token-auth.git"
19 | },
20 | "keywords": [
21 | "angular",
22 | "auth",
23 | "jwt",
24 | "express"
25 | ],
26 | "author": "",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/auth0/angular-token-auth/issues"
30 | },
31 | "homepage": "https://github.com/auth0/angular-token-auth"
32 | }
33 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular Authentication
6 |
7 |
8 |
9 |
10 |
11 |
{{welcome}}
12 |
17 |
{{error}}
18 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## angular-token-auth
2 |
3 | Example of Token-based authentication in [AngularJS](http://angularjs.org) with [Express](http://expressjs.com).
4 |
5 | ### Build and Run
6 |
7 | First, install dependencies using npm:
8 |
9 | ```sh
10 | npm install
11 | ```
12 |
13 | Run the example:
14 |
15 | ```sh
16 | node auth.server.js
17 | ```
18 |
19 | and go to [localhost:8080](http://localhost:8080).
20 |
21 |
22 | ### More advanced scenarios?
23 |
24 | For a complete example handling social providers, enterprise authentication with LDAP/Active Directory, and user/password, check out [Auth0 Angular integration](https://github.com/auth0/auth0-angular).
25 |
26 | ## Issue Reporting
27 |
28 | If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
29 |
30 | ## Author
31 |
32 | [Auth0](auth0.com)
33 |
34 | ## License
35 |
36 | This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
37 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Auth0, Inc. (http://auth0.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/auth.server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var bodyParser = require('body-parser');
3 |
4 | var jwt = require('jsonwebtoken'); //https://npmjs.org/package/node-jsonwebtoken
5 | var expressJwt = require('express-jwt'); //https://npmjs.org/package/express-jwt
6 |
7 |
8 | var secret = 'this is the secret secret secret 12356';
9 |
10 | var app = express();
11 |
12 | // We are going to protect /api routes with JWT
13 | app.use('/api', expressJwt({secret: secret}));
14 |
15 | app.use(bodyParser.json());
16 | app.use('/', express.static(__dirname + '/'));
17 |
18 | app.use(function(err, req, res, next){
19 | if (err.constructor.name === 'UnauthorizedError') {
20 | res.status(401).send('Unauthorized');
21 | }
22 | });
23 |
24 | app.post('/authenticate', function (req, res) {
25 | //TODO validate req.body.username and req.body.password
26 | //if is invalid, return 401
27 | if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
28 | res.status(401).send('Wrong user or password');
29 | return;
30 | }
31 |
32 | var profile = {
33 | first_name: 'John',
34 | last_name: 'Doe',
35 | email: 'john@doe.com',
36 | id: 123
37 | };
38 |
39 | // We are sending the profile inside the token
40 | var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });
41 |
42 | res.json({ token: token });
43 | });
44 |
45 | app.get('/api/restricted', function (req, res) {
46 | console.log('user ' + req.user.email + ' is calling /api/restricted');
47 | res.json({
48 | name: 'foo'
49 | });
50 | });
51 |
52 | app.listen(8080, function () {
53 | console.log('listening on http://localhost:8080');
54 | });
55 |
--------------------------------------------------------------------------------
/auth.client.js:
--------------------------------------------------------------------------------
1 | var myApp = angular.module('myApp', []);
2 |
3 | //this is used to parse the profile
4 | function url_base64_decode(str) {
5 | var output = str.replace('-', '+').replace('_', '/');
6 | switch (output.length % 4) {
7 | case 0:
8 | break;
9 | case 2:
10 | output += '==';
11 | break;
12 | case 3:
13 | output += '=';
14 | break;
15 | default:
16 | throw 'Illegal base64url string!';
17 | }
18 | return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
19 | }
20 |
21 | myApp.controller('UserCtrl', function ($scope, $http, $window) {
22 | $scope.user = {username: 'john.doe', password: 'foobar'};
23 | $scope.isAuthenticated = false;
24 | $scope.welcome = '';
25 | $scope.message = '';
26 |
27 | $scope.submit = function () {
28 | $http
29 | .post('/authenticate', $scope.user)
30 | .success(function (data, status, headers, config) {
31 | $window.sessionStorage.token = data.token;
32 | $scope.isAuthenticated = true;
33 | var encodedProfile = data.token.split('.')[1];
34 | var profile = JSON.parse(url_base64_decode(encodedProfile));
35 | $scope.welcome = 'Welcome ' + profile.first_name + ' ' + profile.last_name;
36 | })
37 | .error(function (data, status, headers, config) {
38 | // Erase the token if the user fails to log in
39 | delete $window.sessionStorage.token;
40 | $scope.isAuthenticated = false;
41 |
42 | // Handle login errors here
43 | $scope.error = 'Error: Invalid user or password';
44 | $scope.welcome = '';
45 | });
46 | };
47 |
48 | $scope.logout = function () {
49 | $scope.welcome = '';
50 | $scope.message = '';
51 | $scope.isAuthenticated = false;
52 | delete $window.sessionStorage.token;
53 | };
54 |
55 | $scope.callRestricted = function () {
56 | $http({url: '/api/restricted', method: 'GET'})
57 | .success(function (data, status, headers, config) {
58 | $scope.message = $scope.message + ' ' + data.name; // Should log 'foo'
59 | })
60 | .error(function (data, status, headers, config) {
61 | alert(data);
62 | });
63 | };
64 |
65 | });
66 |
67 | myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
68 | return {
69 | request: function (config) {
70 | config.headers = config.headers || {};
71 | if ($window.sessionStorage.token) {
72 | config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
73 | }
74 | return config;
75 | },
76 | responseError: function (rejection) {
77 | if (rejection.status === 401) {
78 | // handle the case where the user is not authenticated
79 | }
80 | return $q.reject(rejection);
81 | }
82 | };
83 | });
84 |
85 | myApp.config(function ($httpProvider) {
86 | $httpProvider.interceptors.push('authInterceptor');
87 | });
88 |
--------------------------------------------------------------------------------