├── .gitignore ├── LICENSE ├── docs └── media │ ├── giftdeliveries-client.png │ ├── giftdeliveries-grants.png │ ├── machine-to-machine-samples.png │ ├── worldmappers-rs.png │ └── worldmappers-scopes.png ├── machine-to-machine ├── README.md ├── giftdeliveries-nodejs │ ├── config.json │ ├── index.js │ ├── lib │ │ ├── env.js │ │ └── logger.js │ └── package.json └── worldmappers-api-nodejs │ ├── config.json │ ├── lib │ ├── env.js │ ├── getPublicKey.js │ ├── logger.js │ └── middleware │ │ └── requireScope.js │ ├── package.json │ └── server.js └── user-consent ├── README.md ├── calendarapp-authz-code-nodejs ├── .deployment ├── README.md ├── config.json ├── deploy.sh ├── logger.js ├── package.json ├── server.js └── views │ ├── account.hbs │ ├── appointments.hbs │ ├── contacts.hbs │ ├── index.hbs │ ├── layout │ └── default.hbs │ └── tasks.hbs ├── calendarapp-implicit-jquery ├── .deployment ├── README.MD ├── config.json ├── deploy.sh ├── logger.js ├── package.json ├── server.js └── views │ └── index.hbs ├── organizer-aspnet ├── Api.csproj ├── AppointmentsController.cs ├── ContactsController.cs ├── Model │ ├── Appointment.cs │ ├── Contact.cs │ └── Task.cs ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── RequireScopeAttribute.cs ├── Startup.cs ├── TasksController.cs ├── Web.Debug.config ├── Web.Release.config ├── Web.config └── packages.config └── organizer-nodejs ├── .deployment ├── README.md ├── config.json ├── deploy.sh ├── logger.js ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | 30 | [Oo]bj 31 | [Bb]in 32 | *.user 33 | target 34 | 35 | *.suo 36 | 37 | *.cache 38 | 39 | *.bak 40 | 41 | *.mdf 42 | *.ldf 43 | 44 | TestResults/ 45 | packages 46 | *.tss -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Auth0 Customer Collaboration 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 | 23 | -------------------------------------------------------------------------------- /docs/media/giftdeliveries-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-samples/auth0-api-auth-samples/82e5127d0411c3b9e49eb30d297f59ba403834dd/docs/media/giftdeliveries-client.png -------------------------------------------------------------------------------- /docs/media/giftdeliveries-grants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-samples/auth0-api-auth-samples/82e5127d0411c3b9e49eb30d297f59ba403834dd/docs/media/giftdeliveries-grants.png -------------------------------------------------------------------------------- /docs/media/machine-to-machine-samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-samples/auth0-api-auth-samples/82e5127d0411c3b9e49eb30d297f59ba403834dd/docs/media/machine-to-machine-samples.png -------------------------------------------------------------------------------- /docs/media/worldmappers-rs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-samples/auth0-api-auth-samples/82e5127d0411c3b9e49eb30d297f59ba403834dd/docs/media/worldmappers-rs.png -------------------------------------------------------------------------------- /docs/media/worldmappers-scopes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-samples/auth0-api-auth-samples/82e5127d0411c3b9e49eb30d297f59ba403834dd/docs/media/worldmappers-scopes.png -------------------------------------------------------------------------------- /machine-to-machine/README.md: -------------------------------------------------------------------------------- 1 | # Auth0 API Authorization - Machine to Machine 2 | 3 | These samples show how to setup machine to machine flows using the OAuth2 `client_credentials` flow in Auth0 ([more information](https://auth0.com/docs/api-auth)). 4 | 5 | In this flow you'll have: 6 | 7 | - An Authorization Server (Auth0) 8 | - A Resource Server (your API, in this example the **World Mappers API**) 9 | - One or more Clients (a consumer of the API, in this example **Gift Deliveries**) 10 | 11 | ## World Mappers API 12 | 13 | The team at World Mappers first registered their API [as a Resource Server in Auth0](https://manage.auth0.com/#/apis): 14 | 15 | ![](../docs/media/worldmappers-rs.png) 16 | 17 | After creating the RS they also specified the scopes (permissions) available in this Resource Server: 18 | 19 | ![](../docs/media/worldmappers-scopes.png) 20 | 21 | A client calling this API could be granted any of these scopes. 22 | 23 | The [worldmappers-api-nodejs](./worldmappers-api-nodejs) sample shows how you would configure your API to be a Resource Server. This is pretty straightforward: you accept tokens issued by the Authorization Server (`iss: https://YOUR_DOMAIN/`) to a Resource Server (`aud: urn:worldmappers`). 24 | 25 | By default these tokens will be signed using RS256 so your API will need some logic to retrieve that public key (from: `https://YOUR_DOMAIN/.well-known/jwks.json`). 26 | 27 | And finally your code needs some logic that inspects the contents of the token and validates that the client has the right scope to call a given endpoint: 28 | 29 | ```js 30 | app.get('/api/location/geocode', requireScope('geocode:location'), function(req, res, next) { 31 | res.json({ 32 | lat: 47.6178819, 33 | lng: -122.194041 34 | }); 35 | }); 36 | ``` 37 | 38 | ## Gift Deliveries Client 39 | 40 | After setting up the Resource Server you can register the client for Gift Deliveries. 41 | 42 | ![](../docs/media/giftdeliveries-client.png) 43 | 44 | By default a Client is not authorized to access any of the Resource Servers. Which is why the next step is to authorize the client for the Resource Server and define which scopes are enabled for this client. 45 | 46 | ![](../docs/media/giftdeliveries-grants.png) 47 | 48 | Finally the client can call the `https://YOUR_DOMAIN/oauth/token` endpoint to get an access token which can then be used to call the World Mappers API (RS). 49 | 50 | ```js 51 | var options = { 52 | method: 'POST', 53 | url: 'https://' + env('AUTH0_DOMAIN') + '/oauth/token', 54 | headers: { 55 | 'content-type': 'application/json' 56 | }, 57 | body: { 58 | audience: env('RESOURCE_SERVER'), 59 | grant_type: 'client_credentials', 60 | client_id: env('AUTH0_CLIENT_ID'), 61 | client_secret: env('AUTH0_CLIENT_SECRET') 62 | }, 63 | json: true 64 | }; 65 | 66 | request(options, function(err, res, body) { 67 | if (err || res.statusCode < 200 || res.statusCode >= 300) { 68 | return callback(res && res.body || err); 69 | } 70 | 71 | callback(null, body.access_token); 72 | }); 73 | ``` 74 | 75 | ## Running the Node.js samples 76 | 77 | Before running the Node.js samples make sure you update the `config.json` file in both projects with your own account information. 78 | 79 | ![](../docs/media/machine-to-machine-samples.png) 80 | -------------------------------------------------------------------------------- /machine-to-machine/giftdeliveries-nodejs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESOURCE_SERVER": "urn:worldmappers", 3 | "AUTH0_DOMAIN": "YOUR_DOMAIN", 4 | "AUTH0_CLIENT_ID": "YOUR_CLIENT_ID", 5 | "AUTH0_CLIENT_SECRET": "YOUR_CLIENT_SECRET" 6 | } 7 | -------------------------------------------------------------------------------- /machine-to-machine/giftdeliveries-nodejs/index.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | 3 | var env = require('./lib/env'); 4 | var logger = require('./lib/logger'); 5 | 6 | /* 7 | * Helper method to get an access token from the Authorization Server. 8 | */ 9 | var getAccessToken = function(callback) { 10 | if (!env('AUTH0_DOMAIN')) { 11 | callback(new Error('The AUTH0_DOMAIN is required in order to get an access token (verify your configuration).')); 12 | } 13 | 14 | logger.debug('Fetching access token from https://' + env('AUTH0_DOMAIN') + '/oauth/token'); 15 | 16 | var options = { 17 | method: 'POST', 18 | url: 'https://' + env('AUTH0_DOMAIN') + '/oauth/token', 19 | headers: { 20 | 'cache-control': 'no-cache', 21 | 'content-type': 'application/json' 22 | }, 23 | body: { 24 | audience: env('RESOURCE_SERVER'), 25 | grant_type: 'client_credentials', 26 | client_id: env('AUTH0_CLIENT_ID'), 27 | client_secret: env('AUTH0_CLIENT_SECRET') 28 | }, 29 | json: true 30 | }; 31 | 32 | request(options, function(err, res, body) { 33 | if (err || res.statusCode < 200 || res.statusCode >= 300) { 34 | return callback(res && res.body || err); 35 | } 36 | 37 | callback(null, body.access_token); 38 | }); 39 | } 40 | 41 | logger.info('Starting the Gift Deliveries worker.'); 42 | 43 | // Get the access token. 44 | getAccessToken(function(err, accessToken) { 45 | if (err) { 46 | logger.error('Error getting a token:', err.message || err); 47 | return; 48 | } 49 | 50 | logger.info('Getting directions to the Auth0 Office from the World Mappers API'); 51 | 52 | // Call the Worldmappers API with the access token. 53 | var options = { 54 | url: 'http://localhost:7001/api/directions?destination=Auth0%20Office', 55 | headers: { 56 | Authorization: 'Bearer ' + accessToken 57 | } 58 | } 59 | request.get(options, function(err, res, body) { 60 | if (err || res.statusCode < 200 || res.statusCode >= 300) { 61 | logger.error(res && res.body || err); 62 | } else { 63 | logger.info('Directions:', body); 64 | } 65 | }); 66 | }) 67 | -------------------------------------------------------------------------------- /machine-to-machine/giftdeliveries-nodejs/lib/env.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var nconf = require('nconf'); 3 | 4 | nconf.env() 5 | .file({ file: path.join(__dirname, '../config.json') }) 6 | .defaults({ 7 | PORT: 7001 8 | }); 9 | 10 | module.exports = function(key) { 11 | return nconf.get(key); 12 | }; 13 | -------------------------------------------------------------------------------- /machine-to-machine/giftdeliveries-nodejs/lib/logger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | winston.emitErrs = true; 3 | 4 | var logger = new winston.Logger({ 5 | transports: [ 6 | new winston.transports.Console({ 7 | timestamp: true, 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | module.exports = logger; 18 | module.exports.stream = { 19 | write: function(message, encoding) { 20 | logger.info(message.replace(/\n$/, '')); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /machine-to-machine/giftdeliveries-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "giftdeliveries-nodejs", 3 | "version": "1.0.0", 4 | "description": "Sample client for the Worldmappers API", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "auth0" 11 | ], 12 | "author": "Auth0", 13 | "license": "MIT", 14 | "dependencies": { 15 | "nconf": "^0.8.4", 16 | "request": "^2.72.0", 17 | "winston": "^2.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH0_DOMAIN": "YOUR_DOMAIN", 3 | "RESOURCE_SERVER": "urn:worldmappers" 4 | } 5 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/lib/env.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var nconf = require('nconf'); 3 | 4 | nconf.env() 5 | .file({ file: path.join(__dirname, '../config.json') }) 6 | .defaults({ 7 | PORT: 7001 8 | }); 9 | 10 | module.exports = function(key) { 11 | return nconf.get(key); 12 | }; 13 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/lib/getPublicKey.js: -------------------------------------------------------------------------------- 1 | var ms = require('ms'); 2 | var request = require('request'); 3 | 4 | var logger = require('./logger'); 5 | 6 | function certToPEM (cert) { 7 | cert = cert.match(/.{1,64}/g).join('\n'); 8 | cert = "-----BEGIN CERTIFICATE-----\n" + cert; 9 | cert = cert + "\n-----END CERTIFICATE-----\n"; 10 | return cert; 11 | } 12 | 13 | function getPublicKeyFromJwks(domain, callback) { 14 | var options = { 15 | url: 'https://' + domain + '/.well-known/jwks.json', 16 | json: true 17 | }; 18 | 19 | logger.debug('Loading public key from: https://' + domain + '/.well-known/jwks.json') 20 | request(options, function(err, res) { 21 | if (err || res.statusCode < 200 || res.statusCode >= 300) { 22 | return callback(res && res.body || err); 23 | } 24 | 25 | var key = res.body.keys.find((key) => key.alg === 'RS256'); 26 | if (!key) { 27 | return callback(new Error('Unable to find public key for: ' + domain)); 28 | } 29 | 30 | return callback(null, certToPEM(key.x5c[0])); 31 | }); 32 | } 33 | 34 | module.exports = function(domain) { 35 | if (!domain) { 36 | throw new Error('The domain is required in order to load the public key.'); 37 | } 38 | 39 | var jwksError = null; 40 | var jwksPublicKey = null; 41 | 42 | // Fetch the public key every 10 hours to support key rotation. 43 | const getPublicKey = function() { 44 | getPublicKeyFromJwks(domain, function(err, publicKey) { 45 | if (err) { 46 | jwksError = err; 47 | logger.error('Error loading public key for: ' + domain, err); 48 | } else { 49 | jwksPublicKey = publicKey; 50 | logger.debug('Loaded public key for: ' + domain); 51 | } 52 | }); 53 | }; 54 | getPublicKey(); 55 | setInterval(getPublicKey, ms('10h')); 56 | 57 | // Function to return the public key. 58 | return function(req, header, payload, cb) { 59 | if (!jwksPublicKey) { 60 | return cb(err || new Error('Public key not available.')); 61 | } 62 | 63 | return cb(null, jwksPublicKey); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/lib/logger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | winston.emitErrs = true; 3 | 4 | var logger = new winston.Logger({ 5 | transports: [ 6 | new winston.transports.Console({ 7 | timestamp: true, 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | module.exports = logger; 18 | module.exports.stream = { 19 | write: function(message, encoding) { 20 | logger.info(message.replace(/\n$/, '')); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/lib/middleware/requireScope.js: -------------------------------------------------------------------------------- 1 | module.exports = function(expected_scope){ 2 | return function (req, res, next){ 3 | if (!req.user || !req.user.scope || req.user.scope.split(' ').indexOf(expected_scope) < 0) { 4 | return next(new Error('Cannot perform action. Missing scope ' + expected_scope)); 5 | } 6 | next(); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "worldmappers-nodejs", 3 | "version": "1.0.0", 4 | "description": "Sample Resource Server", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "auth0" 11 | ], 12 | "author": "Auth0", 13 | "license": "MIT", 14 | "dependencies": { 15 | "cors": "^2.7.1", 16 | "express": "^4.13.4", 17 | "express-jwt": "^3.4.0", 18 | "morgan": "^1.7.0", 19 | "ms": "^0.7.1", 20 | "nconf": "^0.8.4", 21 | "request": "^2.72.0", 22 | "winston": "^2.2.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /machine-to-machine/worldmappers-api-nodejs/server.js: -------------------------------------------------------------------------------- 1 | const jwt = require('express-jwt'); 2 | const http = require('http'); 3 | const morgan = require('morgan'); 4 | 5 | const env = require('./lib/env'); 6 | const logger = require('./lib/logger'); 7 | const getPublicKey = require('./lib/getPublicKey'); 8 | const requireScope = require('./lib/middleware/requireScope'); 9 | 10 | /* 11 | * Initialize express. 12 | */ 13 | const express = require('express'); 14 | const app = express(); 15 | app.use(morgan(':method :url :status :response-time ms - :res[content-length]', { 16 | stream: logger.stream 17 | })); 18 | 19 | /* 20 | * Middleware that will validate the incoming access token. 21 | */ 22 | const jwtCheck = jwt({ 23 | secret: getPublicKey(env('AUTH0_DOMAIN')), 24 | audience: env('RESOURCE_SERVER'), 25 | algorithms: [ 'RS256' ], 26 | issuer: `https://${env('AUTH0_DOMAIN')}/` 27 | }); 28 | 29 | /* 30 | * API endpoints. 31 | */ 32 | app.use('/api', jwtCheck, function(req, res, next) { 33 | if (req.user) { 34 | logger.debug('Current user: ' + req.user.sub + ' (scope=' + (req.user.scope || 'N/A') + ')'); 35 | } 36 | next(); 37 | }); 38 | app.get('/api/location/geocode', requireScope('geocode:location'), function(req, res, next) { 39 | res.json({ 40 | lat: 47.6178819, 41 | lng: -122.194041 42 | }); 43 | }); 44 | app.get('/api/location/reverse-geocode', requireScope('reverse-geocode:location'), function(req, res, next) { 45 | res.json({ 46 | street: '10900 NE 8th Street', 47 | city: 'Bellevue', 48 | state: 'Washington' 49 | }); 50 | }); 51 | app.get('/api/directions', requireScope('directions'), function(req, res, next) { 52 | res.json([ 53 | { step: 1, action: 'Turn left' }, 54 | { step: 2, action: 'Turn right' }, 55 | { step: 3, action: 'Finish' } 56 | ]); 57 | }); 58 | 59 | /* 60 | * Error handler 61 | */ 62 | app.use(function(err, req, res, next) { 63 | if (err) { 64 | logger.error('Unauthorized:', err.message); 65 | return res.status(401).send({ message: err.message }); 66 | } 67 | 68 | next(err, req, res); 69 | }); 70 | 71 | /* 72 | * Start server. 73 | */ 74 | http.createServer(app).listen(env('PORT'), function() { 75 | logger.info('Worldmappers API (Resource Server) listening on: http://localhost:' + env('PORT')); 76 | }); 77 | -------------------------------------------------------------------------------- /user-consent/README.md: -------------------------------------------------------------------------------- 1 | # Auth0 API Authorization 2 | 3 | ## User Consent 4 | 5 | These samples show the use case for **Organizer** a platform allowing you to manage your contacts, appointments and tasks. They are now opening up their API to third party applications like **CalendarApp**, a calendar application allowing you to manage your calendars from different providers (Gmail, Outlook, ...) including **Organizer** 6 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | command = bash deploy.sh 3 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/README.md: -------------------------------------------------------------------------------- 1 | # Client: CalendarApp (Node.js - Authorization Code Grant) 2 | 3 | Demo: https://api-authz-calendar-authorization-code.azurewebsites.net/ 4 | 5 | ## Configuration 6 | 7 | Before running this sample you must first make sure your Resource Server is running and you also need to define the Client in Auth0: 8 | 9 | ``` 10 | curl -XPOST 'https://AUTH0_DOMAIN/api/v2/clients' -H "Authorization: Bearer AUTH0_API2_TOKEN" -H "Content-Type: application/json" -d '{ 11 | "name": "Calendar App - Authorization Code", 12 | "resource_servers": [ 13 | { "identifier": "urn:organizer-api", "scopes": [ "appointments", "contacts" ] } 14 | ], 15 | "callbacks": [ "http://localhost:7003/auth/organizer/callback" ] 16 | }' 17 | ``` 18 | 19 | Capture the result from this call, especially the `client_id` and `client_secret` (you will need to enter this in the `config.json` file). 20 | 21 | More information is available [here](https://auth0.com/docs/api-authn-authz#tutorials). 22 | 23 | ## Running the sample 24 | 25 | 1. Update the `config.json` file with your own settings 26 | 2. Run `npm install` 27 | 3. Run `node server` 28 | 4. The web application will start http://localhost:7002 29 | 5. Sign in and try to get your data from the Resource Server 30 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH0_DOMAIN": "{AUTH0_DOMAIN}", 3 | "AUTH0_CLIENT_ID": "{AUTH0_CLIENT_ID}", 4 | "AUTH0_CLIENT_SECRET": "{AUTH0_CLIENT_SECRET}", 5 | "ORGANIZER_BASE_URL": "http://localhost:7001" 6 | } 7 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------- 4 | # KUDU Deployment Script 5 | # Version: 0.2.2 6 | # ---------------------- 7 | 8 | # Helpers 9 | # ------- 10 | 11 | exitWithMessageOnError () { 12 | if [ ! $? -eq 0 ]; then 13 | echo "An error has occurred during web site deployment." 14 | echo $1 15 | exit 1 16 | fi 17 | } 18 | 19 | # Prerequisites 20 | # ------------- 21 | 22 | # Verify node.js installed 23 | hash node 2>/dev/null 24 | exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment." 25 | 26 | # Setup 27 | # ----- 28 | 29 | SCRIPT_DIR="${BASH_SOURCE[0]%\\*}" 30 | SCRIPT_DIR="${SCRIPT_DIR%/*}" 31 | ARTIFACTS=$SCRIPT_DIR/../artifacts 32 | KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"} 33 | 34 | if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then 35 | DEPLOYMENT_SOURCE=$SCRIPT_DIR 36 | fi 37 | 38 | if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then 39 | NEXT_MANIFEST_PATH=$ARTIFACTS/manifest 40 | 41 | if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then 42 | PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH 43 | fi 44 | fi 45 | 46 | if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then 47 | DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot 48 | else 49 | KUDU_SERVICE=true 50 | fi 51 | 52 | if [[ ! -n "$KUDU_SYNC_CMD" ]]; then 53 | # Install kudu sync 54 | echo Installing Kudu Sync 55 | npm install kudusync -g --silent 56 | exitWithMessageOnError "npm failed" 57 | 58 | if [[ ! -n "$KUDU_SERVICE" ]]; then 59 | # In case we are running locally this is the correct location of kuduSync 60 | KUDU_SYNC_CMD=kuduSync 61 | else 62 | # In case we are running on kudu service this is the correct location of kuduSync 63 | KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync 64 | fi 65 | fi 66 | 67 | # Node Helpers 68 | # ------------ 69 | 70 | selectNodeVersion () { 71 | if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then 72 | SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\"" 73 | eval $SELECT_NODE_VERSION 74 | exitWithMessageOnError "select node version failed" 75 | 76 | if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then 77 | NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"` 78 | exitWithMessageOnError "getting node version failed" 79 | fi 80 | 81 | if [[ -e "$DEPLOYMENT_TEMP/.tmp" ]]; then 82 | NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"` 83 | exitWithMessageOnError "getting npm version failed" 84 | fi 85 | 86 | if [[ ! -n "$NODE_EXE" ]]; then 87 | NODE_EXE=node 88 | fi 89 | 90 | NPM_CMD="\"$NODE_EXE\" \"$NPM_JS_PATH\"" 91 | else 92 | NPM_CMD=npm 93 | NODE_EXE=node 94 | fi 95 | } 96 | 97 | ################################################################################################################################## 98 | # Deployment 99 | # ---------- 100 | 101 | echo Handling node.js deployment. 102 | 103 | # 1. KuduSync 104 | if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then 105 | "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh" 106 | exitWithMessageOnError "Kudu Sync failed" 107 | fi 108 | 109 | # 2. Select node version 110 | selectNodeVersion 111 | 112 | # 3. Install npm packages 113 | if [ -e "$DEPLOYMENT_TARGET/package.json" ]; then 114 | cd "$DEPLOYMENT_TARGET" 115 | eval $NPM_CMD install --production 116 | exitWithMessageOnError "npm failed" 117 | cd - > /dev/null 118 | fi 119 | ################################################################################################################################## 120 | 121 | # Post deployment stub 122 | if [[ -n "$POST_DEPLOYMENT_ACTION" ]]; then 123 | POST_DEPLOYMENT_ACTION=${POST_DEPLOYMENT_ACTION//\"} 124 | cd "${POST_DEPLOYMENT_ACTION_DIR%\\*}" 125 | "$POST_DEPLOYMENT_ACTION" 126 | exitWithMessageOnError "post deployment action failed" 127 | fi 128 | 129 | echo "Finished successfully." 130 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/logger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | winston.emitErrs = true; 3 | 4 | var logger = new winston.Logger({ 5 | transports: [ 6 | new winston.transports.Console({ 7 | timestamp: true, 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | module.exports = logger; 18 | module.exports.stream = { 19 | write: function(message, encoding){ 20 | logger.info(message.replace(/\n$/, '')); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "calendarapp-authz-code-nodejs", 3 | "version": "1.0.0", 4 | "engines": { "node": "0.12.0" }, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cookie-parser": "^1.4.0", 14 | "express": "^4.13.3", 15 | "express-hbs": "^0.8.4", 16 | "express-session": "^1.12.1", 17 | "jsonwebtoken": "^5.4.1", 18 | "morgan": "^1.6.1", 19 | "nconf": "^0.8.2", 20 | "passport": "^0.3.2", 21 | "passport-oauth2": "^1.1.2", 22 | "request": "^2.65.0", 23 | "winston": "^2.1.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/server.js: -------------------------------------------------------------------------------- 1 | var jwt = require('jsonwebtoken'); 2 | var http = require('http'); 3 | var path = require('path'); 4 | var morgan = require('morgan'); 5 | var logger = require('./logger'); 6 | var request = require('request'); 7 | 8 | var express = require('express'); 9 | var session = require('express-session'); 10 | var cookieParser = require('cookie-parser'); 11 | var passport = require('passport'); 12 | var oauth2 = require('passport-oauth2'); 13 | var hbs = require('express-hbs'); 14 | 15 | var app = express(); 16 | app.use(cookieParser()); 17 | app.use(session({ secret: 'shhhhhhhhh' })); 18 | app.use(morgan(':method :url :status :response-time ms - :res[content-length]', { 19 | stream: logger.stream 20 | })); 21 | 22 | app.engine('hbs', hbs.express4({ 23 | defaultLayout: path.join(__dirname, 'views/layout/default.hbs') 24 | })); 25 | app.set('view engine', 'hbs'); 26 | app.set('views', path.join(__dirname, 'views')); 27 | 28 | var nconf = require('nconf'); 29 | nconf.env() 30 | .file({ file: './config.json' }) 31 | .defaults({ 32 | PORT: 7003, 33 | CALLBACK_URL: "http://localhost:7003/auth/organizer/callback" 34 | }); 35 | 36 | /* 37 | * Configure passport. 38 | */ 39 | passport.serializeUser(function(user, done) { 40 | console.log('serialize user'); 41 | done(null, user); 42 | }); 43 | passport.deserializeUser(function(user, done) { 44 | console.log('deserialize user'); 45 | done(null, user); 46 | }); 47 | passport.use(new oauth2.Strategy({ 48 | authorizationURL: 'https://' + nconf.get('AUTH0_DOMAIN') + '/i/oauth2/authorize', 49 | tokenURL: 'https://' + nconf.get('AUTH0_DOMAIN') + '/oauth/token', 50 | clientID: nconf.get('AUTH0_CLIENT_ID'), 51 | clientSecret: nconf.get('AUTH0_CLIENT_SECRET'), 52 | callbackURL: nconf.get('CALLBACK_URL'), 53 | skipUserProfile: true 54 | }, function(accessToken, refreshToken, profile, done) { 55 | var payload = jwt.decode(accessToken); 56 | 57 | logger.info('Token received for:', payload.sub); 58 | 59 | done(null, { 60 | id: payload.sub, 61 | access_token: accessToken 62 | }); 63 | })); 64 | 65 | /* 66 | * Initialize passport. 67 | */ 68 | app.use(passport.initialize()); 69 | app.use(passport.session()); 70 | 71 | /* 72 | * Middleware to require authentication. 73 | */ 74 | var requiresLogin = function(req, res, next) { 75 | console.log(req.user); 76 | if (!req.isAuthenticated()) { 77 | return res.redirect('/'); 78 | } 79 | next(); 80 | }; 81 | 82 | /* 83 | * Pages 84 | */ 85 | app.get('/', function(req, res, next) { 86 | res.render('index'); 87 | }); 88 | 89 | app.get('/account', requiresLogin, function(req, res, next) { 90 | res.render('account', { 91 | user: req.user, 92 | user_json: JSON.stringify(req.user, null, 2), 93 | access_token: req.user.access_token, 94 | access_token_payload: JSON.stringify(jwt.decode(req.user.access_token), null, 2) 95 | }); 96 | }); 97 | 98 | app.get('/appointments', requiresLogin, function(req, res, next) { 99 | request({ 100 | url: nconf.get('ORGANIZER_BASE_URL') + '/api/appointments', 101 | json: true, 102 | headers: { 103 | 'Authorization': 'Bearer ' + req.user.access_token 104 | } 105 | }, function(error, response, body) { 106 | if (error) { 107 | logger.error(error); 108 | return res.status(500); 109 | } else { 110 | res.render('appointments', { 111 | user: req.user, 112 | appointments: JSON.stringify(body, null, 2) 113 | }); 114 | } 115 | }); 116 | }); 117 | 118 | app.get('/contacts', requiresLogin, function(req, res, next) { 119 | request({ 120 | url: nconf.get('ORGANIZER_BASE_URL') + '/api/contacts', 121 | json: true, 122 | headers: { 123 | 'Authorization': 'Bearer ' + req.user.access_token 124 | } 125 | }, function(error, response, body) { 126 | if (error) { 127 | logger.error(error); 128 | return res.status(500); 129 | } else { 130 | res.render('contacts', { 131 | user: req.user, 132 | contacts: JSON.stringify(body, null, 2) 133 | }); 134 | } 135 | }); 136 | }); 137 | 138 | app.get('/tasks', requiresLogin, function(req, res, next) { 139 | request({ 140 | url: nconf.get('ORGANIZER_BASE_URL') + '/api/tasks', 141 | json: true, 142 | headers: { 143 | 'Authorization': 'Bearer ' + req.user.access_token 144 | } 145 | }, function(error, response, body) { 146 | if (error) { 147 | logger.error(error); 148 | return res.status(500); 149 | } else { 150 | res.render('tasks', { 151 | user: req.user, 152 | tasks: JSON.stringify(body, null, 2) 153 | }); 154 | } 155 | }); 156 | }); 157 | 158 | /* 159 | * Login with 'Organizer' (the Resource Server) 160 | */ 161 | app.get('/auth/organizer', 162 | passport.authenticate('oauth2', { scope: 'appointments contacts openid email' })); 163 | 164 | /* 165 | * Handle callback from the Authorization Server. 166 | */ 167 | app.get('/auth/organizer/callback', 168 | passport.authenticate('oauth2', { failureRedirect: '/' }), 169 | function(req, res) { 170 | logger.debug('Login:', req.user.access_token); 171 | res.redirect('/account'); 172 | }); 173 | /* 174 | * Start server. 175 | */ 176 | http.createServer(app).listen(nconf.get('PORT'), function() { 177 | logger.info('CalendarApp listening on: http://localhost:' + nconf.get('PORT')); 178 | logger.info(' > Mode: client - authorization code grant'); 179 | }); 180 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/account.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Actions

5 | Get Appointments from OrganizerApp 6 | Get Contacts from OrganizerApp 7 | Get Tasks from OrganizerApp 8 | 9 |

User

10 |

Here is the current user object:

11 |
{{ user_json }}
12 | 13 |

Token

14 |

Here is the access_token issued by the Authorization Server.

15 |
{{ access_token }}
16 |

And these are the contents of the access_token.

17 |
{{ access_token_payload }}
18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/appointments.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Actions

5 | My Account 6 | Get Contacts from OrganizerApp 7 | Get Tasks from OrganizerApp 8 | 9 |

Appointments

10 |

These are the appointments for {{ user.id }} we received from Oranizer (by calling the API on your behalf)

11 |
{{ appointments }}
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/contacts.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Actions

5 | My Account 6 | Get Appointments from OrganizerApp 7 | Get Tasks from OrganizerApp 8 | 9 |

Contacts

10 |

These are the contacts for {{ user.id }} we received from Oranizer (by calling the API on your behalf)

11 |
{{ contacts }}
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/index.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Authorization

5 |

Request authorization from "Organizer" to access your appointments.

6 |
7 | Sign In with Organizer 8 |
9 | 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/layout/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

CalendarApp

10 |

(authorization code grant - Node.js)

11 |
12 |
13 | {{{ body }}} 14 | 15 | 16 | {{{ block 'scripts' }}} 17 | 18 | 19 | -------------------------------------------------------------------------------- /user-consent/calendarapp-authz-code-nodejs/views/tasks.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Actions

5 | My Account 6 | Get Appointments from OrganizerApp 7 | Get Tasks from OrganizerApp 8 | 9 |

Tasks

10 |

This is the response we received from Oranizer when trying to get the tasks for your account. Remember that you did not give consent for tasks, so CalenderApp should not be allowed to access this data.

11 |
{{ tasks }}
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | command = bash deploy.sh 3 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/README.MD: -------------------------------------------------------------------------------- 1 | # Client: CalendarApp (jQuery - Implicit Grant) 2 | 3 | Demo: http://api-authz-calendar-implicit.azurewebsites.net/ 4 | 5 | ## Configuration 6 | 7 | Before running this sample you must first make sure your Resource Server is running and you also need to define the Client in Auth0: 8 | 9 | ``` 10 | curl -XPOST 'https://AUTH0_DOMAIN/api/v2/clients' -H "Authorization: Bearer AUTH0_API2_TOKEN" -H "Content-Type: application/json" -d '{ 11 | "name": "Calendar App - Implicit", 12 | "resource_servers": [ 13 | { "identifier": "urn:organizer-api", "scopes": [ "appointments", "contacts" ] } 14 | ], 15 | "callbacks": [ "http://localhost:7002" ] 16 | }' 17 | ``` 18 | 19 | Capture the result from this call, especially the `client_id` (you will need to enter this in the `config.json` file). 20 | 21 | More information is available [here](https://auth0.com/docs/api-authn-authz#tutorials). 22 | 23 | ## Running the sample 24 | 25 | 1. Update the `config.json` file with your own settings 26 | 2. Run `npm install` 27 | 3. Run `node server` 28 | 4. The web application will start http://localhost:7002 29 | 5. Sign in and try to get your data from the Resource Server 30 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH0_DOMAIN": "{AUTH0_DOMAIN}", 3 | "AUTH0_CLIENT_ID": "{AUTH0_CLIENT_ID}" 4 | } 5 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------- 4 | # KUDU Deployment Script 5 | # Version: 0.2.2 6 | # ---------------------- 7 | 8 | # Helpers 9 | # ------- 10 | 11 | exitWithMessageOnError () { 12 | if [ ! $? -eq 0 ]; then 13 | echo "An error has occurred during web site deployment." 14 | echo $1 15 | exit 1 16 | fi 17 | } 18 | 19 | # Prerequisites 20 | # ------------- 21 | 22 | # Verify node.js installed 23 | hash node 2>/dev/null 24 | exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment." 25 | 26 | # Setup 27 | # ----- 28 | 29 | SCRIPT_DIR="${BASH_SOURCE[0]%\\*}" 30 | SCRIPT_DIR="${SCRIPT_DIR%/*}" 31 | ARTIFACTS=$SCRIPT_DIR/../artifacts 32 | KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"} 33 | 34 | if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then 35 | DEPLOYMENT_SOURCE=$SCRIPT_DIR 36 | fi 37 | 38 | if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then 39 | NEXT_MANIFEST_PATH=$ARTIFACTS/manifest 40 | 41 | if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then 42 | PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH 43 | fi 44 | fi 45 | 46 | if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then 47 | DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot 48 | else 49 | KUDU_SERVICE=true 50 | fi 51 | 52 | if [[ ! -n "$KUDU_SYNC_CMD" ]]; then 53 | # Install kudu sync 54 | echo Installing Kudu Sync 55 | npm install kudusync -g --silent 56 | exitWithMessageOnError "npm failed" 57 | 58 | if [[ ! -n "$KUDU_SERVICE" ]]; then 59 | # In case we are running locally this is the correct location of kuduSync 60 | KUDU_SYNC_CMD=kuduSync 61 | else 62 | # In case we are running on kudu service this is the correct location of kuduSync 63 | KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync 64 | fi 65 | fi 66 | 67 | # Node Helpers 68 | # ------------ 69 | 70 | selectNodeVersion () { 71 | if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then 72 | SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\"" 73 | eval $SELECT_NODE_VERSION 74 | exitWithMessageOnError "select node version failed" 75 | 76 | if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then 77 | NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"` 78 | exitWithMessageOnError "getting node version failed" 79 | fi 80 | 81 | if [[ -e "$DEPLOYMENT_TEMP/.tmp" ]]; then 82 | NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"` 83 | exitWithMessageOnError "getting npm version failed" 84 | fi 85 | 86 | if [[ ! -n "$NODE_EXE" ]]; then 87 | NODE_EXE=node 88 | fi 89 | 90 | NPM_CMD="\"$NODE_EXE\" \"$NPM_JS_PATH\"" 91 | else 92 | NPM_CMD=npm 93 | NODE_EXE=node 94 | fi 95 | } 96 | 97 | ################################################################################################################################## 98 | # Deployment 99 | # ---------- 100 | 101 | echo Handling node.js deployment. 102 | 103 | # 1. KuduSync 104 | if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then 105 | "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh" 106 | exitWithMessageOnError "Kudu Sync failed" 107 | fi 108 | 109 | # 2. Select node version 110 | selectNodeVersion 111 | 112 | # 3. Install npm packages 113 | if [ -e "$DEPLOYMENT_TARGET/package.json" ]; then 114 | cd "$DEPLOYMENT_TARGET" 115 | eval $NPM_CMD install --production 116 | exitWithMessageOnError "npm failed" 117 | cd - > /dev/null 118 | fi 119 | ################################################################################################################################## 120 | 121 | # Post deployment stub 122 | if [[ -n "$POST_DEPLOYMENT_ACTION" ]]; then 123 | POST_DEPLOYMENT_ACTION=${POST_DEPLOYMENT_ACTION//\"} 124 | cd "${POST_DEPLOYMENT_ACTION_DIR%\\*}" 125 | "$POST_DEPLOYMENT_ACTION" 126 | exitWithMessageOnError "post deployment action failed" 127 | fi 128 | 129 | echo "Finished successfully." 130 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/logger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | winston.emitErrs = true; 3 | 4 | var logger = new winston.Logger({ 5 | transports: [ 6 | new winston.transports.Console({ 7 | timestamp: true, 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | module.exports = logger; 18 | module.exports.stream = { 19 | write: function(message, encoding){ 20 | logger.info(message.replace(/\n$/, '')); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "calendarapp-implicit-jquery", 3 | "version": "1.0.0", 4 | "engines": { "node": "0.12.0" }, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.13.3", 14 | "express-hbs": "^0.8.4", 15 | "morgan": "^1.6.1", 16 | "nconf": "^0.8.2", 17 | "winston": "^2.1.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var path = require('path'); 3 | var morgan = require('morgan'); 4 | var logger = require('./logger'); 5 | 6 | var express = require('express'); 7 | var hbs = require('express-hbs'); 8 | var app = express(); 9 | app.use(morgan(':method :url :status :response-time ms - :res[content-length]', { 10 | stream: logger.stream 11 | })); 12 | 13 | app.engine('hbs', hbs.express4()); 14 | app.set('view engine', 'hbs'); 15 | app.set('views', path.join(__dirname, 'views')); 16 | 17 | var nconf = require('nconf'); 18 | nconf.env() 19 | .file({ file: './config.json' }) 20 | .defaults({ 21 | PORT: 7002, 22 | CALLBACK_URL: "http://localhost:7002", 23 | ORGANIZER_BASE_URL: "http://localhost:7001" 24 | }); 25 | 26 | var callback_url = nconf.get('CALLBACK_URL'); 27 | var authorize_url = "https://{AUTH0_DOMAIN}/i/oauth2/authorize?scope=appointments%20contacts&response_type=token&client_id={AUTH0_CLIENT_ID}&redirect_uri={CALLBACK_URL}" 28 | .replace(/({AUTH0_DOMAIN})/g, nconf.get('AUTH0_DOMAIN')) 29 | .replace(/({AUTH0_CLIENT_ID})/g, nconf.get('AUTH0_CLIENT_ID')) 30 | .replace(/({CALLBACK_URL})/g, callback_url); 31 | 32 | /* 33 | * Serve HTML page. 34 | */ 35 | app.get('/', function(req, res, next) { 36 | res.render('index', { 37 | callback_url: callback_url, 38 | authorize_url: authorize_url, 39 | organizer_base_url: nconf.get('ORGANIZER_BASE_URL'), 40 | auth0_domain: nconf.get('AUTH0_DOMAIN'), 41 | auth0_client_id: nconf.get('AUTH0_CLIENT_ID') 42 | }); 43 | }); 44 | 45 | /* 46 | * Start server. 47 | */ 48 | http.createServer(app).listen(nconf.get('PORT'), function() { 49 | logger.info('CalendarApp (Client) listening on: http://localhost:' + nconf.get('PORT')); 50 | }); 51 | -------------------------------------------------------------------------------- /user-consent/calendarapp-implicit-jquery/views/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

CalendarApp (implicit grant - jQuery)

10 |
11 |
12 |
13 |
14 |
15 |

Authorization

16 |

Request authorization from "Organizer" to access your appointments.

17 |
18 | Sign In with Organizer 19 |
20 | 21 |
22 |
23 | 39 |
40 | 41 | 42 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {1CB5EFD1-02FE-4110-9DF8-0F70BF66B82C} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | Api 15 | Api 16 | v4.5 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | pdbonly 37 | true 38 | bin\ 39 | TRACE 40 | prompt 41 | 4 42 | 43 | 44 | 45 | 46 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll 47 | 48 | 49 | False 50 | ..\packages\Microsoft.Owin.Cors.3.0.1\lib\net45\Microsoft.Owin.Cors.dll 51 | 52 | 53 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 54 | True 55 | 56 | 57 | False 58 | ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll 59 | 60 | 61 | ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll 62 | 63 | 64 | ..\packages\Microsoft.Owin.Security.ActiveDirectory.3.0.1\lib\net45\Microsoft.Owin.Security.ActiveDirectory.dll 65 | 66 | 67 | ..\packages\Microsoft.Owin.Security.Jwt.3.0.1\lib\net45\Microsoft.Owin.Security.Jwt.dll 68 | 69 | 70 | ..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll 71 | 72 | 73 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll 74 | True 75 | 76 | 77 | ..\packages\Owin.1.0\lib\net40\Owin.dll 78 | 79 | 80 | 81 | ..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll 82 | True 83 | 84 | 85 | 86 | False 87 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 88 | 89 | 90 | 91 | False 92 | ..\packages\Microsoft.AspNet.Cors.5.2.3\lib\net45\System.Web.Cors.dll 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | False 105 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 106 | 107 | 108 | False 109 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll 110 | 111 | 112 | False 113 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | Web.config 128 | 129 | 130 | Web.config 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 10.0 149 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | True 159 | True 160 | 1123 161 | / 162 | http://localhost:7001 163 | False 164 | False 165 | 166 | 167 | False 168 | 169 | 170 | 171 | 172 | 179 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/AppointmentsController.cs: -------------------------------------------------------------------------------- 1 | using Api.Model; 2 | using System; 3 | using System.Web.Http; 4 | 5 | namespace Api 6 | { 7 | public class AppointmentsController : ApiController 8 | { 9 | [Authorize, RequireScope("appointments")] 10 | [HttpGet, Route("api/appointments")] 11 | public IHttpActionResult Get() 12 | { 13 | return this.Ok(new [] 14 | { 15 | new Appointment(new DateTime(2015, 11, 20), "Meet with Fabrikam"), 16 | new Appointment(new DateTime(2015, 11, 3), "Follow up on deal with Contoso") 17 | }); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/ContactsController.cs: -------------------------------------------------------------------------------- 1 | using Api.Model; 2 | 3 | using System.Web.Http; 4 | 5 | namespace Api 6 | { 7 | public class ContactsController : ApiController 8 | { 9 | [Authorize, RequireScope("contacts")] 10 | [HttpGet, Route("api/contacts")] 11 | public IHttpActionResult Get() 12 | { 13 | return this.Ok(new [] 14 | { 15 | new Contact("John Doe", "john.doe@gmail.com"), 16 | new Contact("Jane Doe", "jane.doe@gmail.com") 17 | }); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Model/Appointment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Api.Model 4 | { 5 | public class Appointment 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public string Subject { get; set; } 10 | 11 | public Appointment(DateTime date, string subject) 12 | { 13 | Date = date; 14 | Subject = subject; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Model/Contact.cs: -------------------------------------------------------------------------------- 1 | namespace Api.Model 2 | { 3 | public class Contact 4 | { 5 | public string Name { get; set; } 6 | 7 | public string Email { get; set; } 8 | 9 | public Contact(string name, string email) 10 | { 11 | Name = name; 12 | Email = email; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Model/Task.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Api.Model 4 | { 5 | public class Task 6 | { 7 | public DateTime DueDate { get; set; } 8 | 9 | public string Title { get; set; } 10 | 11 | public Task(DateTime dueDate, string title) 12 | { 13 | DueDate = dueDate; 14 | Title = title; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Api")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Api")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("16395c6c-e3ba-4dcb-824d-eecd490cbd2a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/README.md: -------------------------------------------------------------------------------- 1 | # Resource Server: Organizer (ASP.NET Web API) 2 | 3 | ## Configuration 4 | 5 | Before running this sample you must first define the Resource Server in Auth0: 6 | 7 | ``` 8 | curl -XPOST 'https://AUTH0_DOMAIN/api/v2/resource-servers' -H "Authorization: Bearer AUTH0_API2_TOKEN" -H "Content-Type: application/json" -d '{ 9 | "identifier": "urn:organizer-api", 10 | "scopes": [ 11 | { "value": "contacts", "description": "Manage your contacts" }, 12 | { "value": "appointments", "description": "Manage your appointments" }, 13 | { "value": "tasks", "description": "Manage your tasks" } 14 | ] 15 | }' 16 | ``` 17 | 18 | More information is available [here](https://auth0.com/docs/api-authn-authz#tutorials). 19 | 20 | ## Running the sample 21 | 22 | 1. Update the `web.config` file with your own settings 23 | 2. Start the project 24 | 3. The API will be listening on http://localhost:7001 25 | 4. Now use one of the clients to connect to the API 26 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/RequireScopeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using System.Security.Claims; 3 | 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Web.Http.Filters; 8 | using System.Web.Http.Controllers; 9 | using System; 10 | 11 | namespace Api 12 | { 13 | public class RequireScopeAttribute : AuthorizationFilterAttribute 14 | { 15 | public string Scope { get; set; } 16 | 17 | public RequireScopeAttribute(string scope) 18 | { 19 | this.Scope = scope; 20 | } 21 | 22 | public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) 23 | { 24 | var principal = actionContext.RequestContext.Principal as ClaimsPrincipal; 25 | if (!HasScopeClaim(principal, Scope)) 26 | { 27 | actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, 28 | new { reason = string.Format("User is missing the {0} scope.", Scope) }); 29 | return Task.FromResult(null); 30 | } 31 | 32 | return Task.FromResult(null); 33 | } 34 | 35 | private bool HasScopeClaim(ClaimsPrincipal principal, string scope) 36 | { 37 | if (principal == null || !principal.Identity.IsAuthenticated) 38 | { 39 | return false; 40 | } 41 | 42 | var claim = principal.FindFirst(c => c.Type == "scope"); 43 | return claim != null && !String.IsNullOrEmpty(claim.Value) && 44 | (claim.Value == scope || (claim.Value.Contains(" ") && claim.Value.Split(' ').Any(s => s == scope))); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Startup.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Web.Http; 3 | using System.IdentityModel.Tokens; 4 | 5 | using Api; 6 | 7 | using Owin; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Cors; 10 | using Microsoft.Owin.Security.ActiveDirectory; 11 | using System.Configuration; 12 | 13 | [assembly: OwinStartup(typeof(Startup))] 14 | 15 | namespace Api 16 | { 17 | public class Startup 18 | { 19 | public void Configuration(IAppBuilder app) 20 | { 21 | var issuer = "https://" + ConfigurationManager.AppSettings["auth0:Domain"] + "/"; 22 | var audience = ConfigurationManager.AppSettings["auth0:ResourceServer"]; 23 | 24 | app.UseCors(CorsOptions.AllowAll); 25 | app.UseActiveDirectoryFederationServicesBearerAuthentication( 26 | new ActiveDirectoryFederationServicesBearerAuthenticationOptions 27 | { 28 | TokenValidationParameters = new TokenValidationParameters 29 | { 30 | ValidAudience = audience, 31 | ValidIssuer = issuer, 32 | IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => 33 | parameters.IssuerSigningTokens.FirstOrDefault().SecurityKeys.FirstOrDefault() 34 | }, 35 | MetadataEndpoint = string.Format("{0}/wsfed/FederationMetadata/2007-06/FederationMetadata.xml", issuer.TrimEnd('/')) 36 | }); 37 | 38 | var configuration = new HttpConfiguration(); 39 | configuration.MapHttpAttributeRoutes(); 40 | configuration.Routes.MapHttpRoute( 41 | name: "DefaultApi", 42 | routeTemplate: "api/{controller}/{id}", 43 | defaults: new { id = RouteParameter.Optional } 44 | ); 45 | app.UseWebApi(configuration); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/TasksController.cs: -------------------------------------------------------------------------------- 1 | using Api.Model; 2 | 3 | using System; 4 | using System.Web.Http; 5 | 6 | namespace Api 7 | { 8 | public class TasksController : ApiController 9 | { 10 | [Authorize, RequireScope("tasks")] 11 | [HttpGet, Route("api/tasks")] 12 | public IHttpActionResult Get() 13 | { 14 | return this.Ok(new [] 15 | { 16 | new Task(new DateTime(2015, 12, 5), "Finish blog post") 17 | }); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /user-consent/organizer-aspnet/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | command = bash deploy.sh 3 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/README.md: -------------------------------------------------------------------------------- 1 | # Resource Server: Organizer (Node.js) 2 | 3 | ## Configuration 4 | 5 | Before running this sample you must first define the Resource Server in Auth0: 6 | 7 | ``` 8 | curl -XPOST 'https://AUTH0_DOMAIN/api/v2/resource-servers' -H "Authorization: Bearer AUTH0_API2_TOKEN" -H "Content-Type: application/json" -d '{ 9 | "identifier": "urn:organizer-api", 10 | "scopes": [ 11 | { "value": "contacts", "description": "Manage your contacts" }, 12 | { "value": "appointments", "description": "Manage your appointments" }, 13 | { "value": "tasks", "description": "Manage your tasks" } 14 | ] 15 | }' 16 | ``` 17 | 18 | More information is available [here](https://auth0.com/docs/api-authn-authz#tutorials). 19 | 20 | ## Running the sample 21 | 22 | 1. Store the public key in the root: `curl -o key.pem https://AUTH_DOMAIN/pem` 23 | 1. Update the `config.json` file with your own settings 24 | 2. Run `npm install` 25 | 3. Run `node server` 26 | 4. The API will be listening on http://localhost:7001 27 | 5. Now use one of the clients to connect to the API 28 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH0_DOMAIN": "{AUTH0_DOMAIN}", 3 | "RESOURCE_SERVER": "urn:organizer" 4 | } 5 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------- 4 | # KUDU Deployment Script 5 | # Version: 0.2.2 6 | # ---------------------- 7 | 8 | # Helpers 9 | # ------- 10 | 11 | exitWithMessageOnError () { 12 | if [ ! $? -eq 0 ]; then 13 | echo "An error has occurred during web site deployment." 14 | echo $1 15 | exit 1 16 | fi 17 | } 18 | 19 | # Prerequisites 20 | # ------------- 21 | 22 | # Verify node.js installed 23 | hash node 2>/dev/null 24 | exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment." 25 | 26 | # Setup 27 | # ----- 28 | 29 | SCRIPT_DIR="${BASH_SOURCE[0]%\\*}" 30 | SCRIPT_DIR="${SCRIPT_DIR%/*}" 31 | ARTIFACTS=$SCRIPT_DIR/../artifacts 32 | KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"} 33 | 34 | if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then 35 | DEPLOYMENT_SOURCE=$SCRIPT_DIR 36 | fi 37 | 38 | if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then 39 | NEXT_MANIFEST_PATH=$ARTIFACTS/manifest 40 | 41 | if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then 42 | PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH 43 | fi 44 | fi 45 | 46 | if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then 47 | DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot 48 | else 49 | KUDU_SERVICE=true 50 | fi 51 | 52 | if [[ ! -n "$KUDU_SYNC_CMD" ]]; then 53 | # Install kudu sync 54 | echo Installing Kudu Sync 55 | npm install kudusync -g --silent 56 | exitWithMessageOnError "npm failed" 57 | 58 | if [[ ! -n "$KUDU_SERVICE" ]]; then 59 | # In case we are running locally this is the correct location of kuduSync 60 | KUDU_SYNC_CMD=kuduSync 61 | else 62 | # In case we are running on kudu service this is the correct location of kuduSync 63 | KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync 64 | fi 65 | fi 66 | 67 | # Node Helpers 68 | # ------------ 69 | 70 | selectNodeVersion () { 71 | if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then 72 | SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\"" 73 | eval $SELECT_NODE_VERSION 74 | exitWithMessageOnError "select node version failed" 75 | 76 | if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then 77 | NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"` 78 | exitWithMessageOnError "getting node version failed" 79 | fi 80 | 81 | if [[ -e "$DEPLOYMENT_TEMP/.tmp" ]]; then 82 | NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"` 83 | exitWithMessageOnError "getting npm version failed" 84 | fi 85 | 86 | if [[ ! -n "$NODE_EXE" ]]; then 87 | NODE_EXE=node 88 | fi 89 | 90 | NPM_CMD="\"$NODE_EXE\" \"$NPM_JS_PATH\"" 91 | else 92 | NPM_CMD=npm 93 | NODE_EXE=node 94 | fi 95 | } 96 | 97 | ################################################################################################################################## 98 | # Deployment 99 | # ---------- 100 | 101 | echo Handling node.js deployment. 102 | 103 | # 1. KuduSync 104 | if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then 105 | "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh" 106 | exitWithMessageOnError "Kudu Sync failed" 107 | fi 108 | 109 | # 2. Select node version 110 | selectNodeVersion 111 | 112 | # 3. Install npm packages 113 | if [ -e "$DEPLOYMENT_TARGET/package.json" ]; then 114 | cd "$DEPLOYMENT_TARGET" 115 | eval $NPM_CMD install --production 116 | exitWithMessageOnError "npm failed" 117 | cd - > /dev/null 118 | fi 119 | ################################################################################################################################## 120 | 121 | # Post deployment stub 122 | if [[ -n "$POST_DEPLOYMENT_ACTION" ]]; then 123 | POST_DEPLOYMENT_ACTION=${POST_DEPLOYMENT_ACTION//\"} 124 | cd "${POST_DEPLOYMENT_ACTION_DIR%\\*}" 125 | "$POST_DEPLOYMENT_ACTION" 126 | exitWithMessageOnError "post deployment action failed" 127 | fi 128 | 129 | echo "Finished successfully." 130 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/logger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | winston.emitErrs = true; 3 | 4 | var logger = new winston.Logger({ 5 | transports: [ 6 | new winston.transports.Console({ 7 | timestamp: true, 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | module.exports = logger; 18 | module.exports.stream = { 19 | write: function(message, encoding){ 20 | logger.info(message.replace(/\n$/, '')); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "organizer-nodejs", 3 | "version": "1.0.0", 4 | "engines": { "node": "0.12.0" }, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Auth0", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.7.1", 14 | "express": "^4.13.3", 15 | "express-jwt": "^3.3.0", 16 | "morgan": "^1.6.1", 17 | "nconf": "^0.8.2", 18 | "winston": "^2.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /user-consent/organizer-nodejs/server.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var jwt = require('express-jwt'); 3 | var http = require('http'); 4 | var cors = require('cors'); 5 | var morgan = require('morgan'); 6 | var logger = require('./logger'); 7 | var publicKey = fs.readFileSync('./key.pem'); 8 | 9 | var express = require('express'); 10 | var app = express(); 11 | app.use(cors()); 12 | app.use(morgan(':method :url :status :response-time ms - :res[content-length]', { 13 | stream: logger.stream 14 | })); 15 | 16 | var nconf = require('nconf'); 17 | nconf.env() 18 | .file({ file: './config.json' }) 19 | .defaults({ 20 | PORT: 7001 21 | }); 22 | 23 | /* 24 | * Middleware that will validate the incoming access token. 25 | */ 26 | var jwtCheck = jwt({ 27 | secret: publicKey, 28 | audience: nconf.get('RESOURCE_SERVER'), 29 | issuer: 'https://' + nconf.get('AUTH0_DOMAIN') + '/' 30 | }); 31 | 32 | /* 33 | * Middleware that checks if a scope is available in the current user. 34 | */ 35 | var requireScope = function(expected_scope){ 36 | return function (req, res, next){ 37 | if (!req.user || req.user.scope.split(' ').indexOf(expected_scope) < 0) { 38 | return next(new Error('Cannot perform action. Missing scope ' + expected_scope)); 39 | } 40 | next(); 41 | }; 42 | }; 43 | 44 | /* 45 | * API endpoints. 46 | */ 47 | app.use('/api', jwtCheck, function(req, res, next) { 48 | if (req.user) { 49 | logger.debug('Current user: ' + req.user.sub + ' (scope=' + req.user.scope + ')'); 50 | } 51 | next(); 52 | }); 53 | app.get('/api/appointments', requireScope('appointments'), function(req, res, next) { 54 | res.json([ 55 | { subject: 'Meet with Fabrikam', date: '2015-11-20' }, 56 | { subject: 'Follow up on deal with Contoso', date: '2015-12-03' } 57 | ]); 58 | }); 59 | app.get('/api/contacts', requireScope('contacts'), function(req, res, next) { 60 | res.json([ 61 | { name: 'John Doe', email: 'john.doe@gmail.com' }, 62 | { name: 'Jane Doe', email: 'jane.doe@gmail.com' } 63 | ]); 64 | }); 65 | app.get('/api/tasks', requireScope('tasks'), function(req, res, next) { 66 | res.json([ 67 | { title: 'Finish blog post', due_date: '2015-12-05' } 68 | ]); 69 | }); 70 | 71 | /* 72 | * Error handler 73 | */ 74 | app.use(function(err, req, res, next) { 75 | if (err) { 76 | logger.error('Unauthorized:', err.message); 77 | return res.status(401).send({ message: err.message }); 78 | } 79 | 80 | next(err, req, res); 81 | }); 82 | 83 | /* 84 | * Start server. 85 | */ 86 | http.createServer(app).listen(nconf.get('PORT'), function() { 87 | logger.info('Organizer API (Resource Server) listening on: http://localhost:' + nconf.get('PORT')); 88 | }); 89 | --------------------------------------------------------------------------------