├── .gitignore ├── README.md ├── example-oauth2orize-consumer.js ├── oauth-config.js ├── oauth-consumer-config.js ├── package.json ├── passport-example ├── profile.js └── strategy.js ├── public ├── error.jade ├── index.jade └── success.jade ├── server.js └── user.js /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw* 2 | node_modules 3 | *~ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moved 2 | ### [example-oauth2orize-consumer](https://git.daplie.com/coolaj86/example-oauth2orize-consumer) is now at [git.daplie.com/coolaj86/example-oauth2orize-consumer](https://git.daplie.com/coolaj86/example-oauth2orize-consumer) 3 | -------------------------------------------------------------------------------- /example-oauth2orize-consumer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | var util = require('util') 7 | , OAuth2Strategy = require('passport-oauth').OAuth2Strategy 8 | , InternalOAuthError = require('passport-oauth').InternalOAuthError 9 | , pConf = require('./provider-config') 10 | ; 11 | 12 | /** 13 | * `Strategy` constructor. 14 | * 15 | * The example-oauth2orize authentication strategy authenticates requests by delegating to 16 | * example-oauth2orize using the OAuth 2.0 protocol. 17 | * 18 | * Applications must supply a `verify` callback which accepts an `accessToken`, 19 | * `refreshToken` and service-specific `profile`, and then calls the `done` 20 | * callback supplying a `user`, which should be set to `false` if the 21 | * credentials are not valid. If an exception occured, `err` should be set. 22 | * 23 | * Options: 24 | * - `clientID` your example-oauth2orize application's client id 25 | * - `clientSecret` your example-oauth2orize application's client secret 26 | * - `callbackURL` URL to which example-oauth2orize will redirect the user after granting authorization 27 | * 28 | * Examples: 29 | * 30 | * passport.use(new Thirty7SignalsStrategy({ 31 | * clientID: '123-456-789', 32 | * clientSecret: 'shhh-its-a-secret' 33 | * callbackURL: 'https://www.example.net/auth/example-oauth2orize/callback' 34 | * }, 35 | * function(accessToken, refreshToken, profile, done) { 36 | * User.findOrCreate(..., function (err, user) { 37 | * done(err, user); 38 | * }); 39 | * } 40 | * )); 41 | * 42 | * @param {Object} options 43 | * @param {Function} verify 44 | * @api public 45 | */ 46 | function Strategy(options, verify) { 47 | options = options || {}; 48 | options.authorizationURL = options.authorizationURL || (pConf.protocol + '://' + pConf.host + '/dialog/authorize'); 49 | options.tokenURL = options.tokenURL || (pConf.protocol + '://' + pConf.host + '/oauth/token'); 50 | 51 | OAuth2Strategy.call(this, options, verify); 52 | this.name = 'example-oauth2orize'; 53 | } 54 | 55 | /** 56 | * Inherit from `OAuth2Strategy`. 57 | */ 58 | util.inherits(Strategy, OAuth2Strategy); 59 | 60 | 61 | /** 62 | * Retrieve user profile from example-oauth2orize. 63 | * 64 | * This function constructs a normalized profile, with the following properties: 65 | * 66 | * - `provider` always set to `example-oauth2orize` 67 | * - `id` 68 | * - `username` 69 | * - `displayName` 70 | * 71 | * @param {String} accessToken 72 | * @param {Function} done 73 | * @api protected 74 | */ 75 | Strategy.prototype.userProfile = function(accessToken, done) { 76 | this._oauth2.get(pConf.protocol + '://' + pConf.host + '/api/userinfo', accessToken, function (err, body/*, res*/) { 77 | if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); } 78 | 79 | try { 80 | var json = JSON.parse(body) 81 | , profile = { provider: 'example-oauth2orize' } 82 | ; 83 | 84 | console.log(json); 85 | /* 86 | profile.id = json.identity.id; 87 | profile.displayName = json.identity.first_name + ' ' + json.identity.last_name; 88 | profile.name = { familyName: json.identity.last_name, 89 | givenName: json.identity.first_name }; 90 | profile.emails = [{ value: json.identity.email_address }]; 91 | 92 | profile._raw = body; 93 | */ 94 | profile._json = json; 95 | 96 | done(null, profile); 97 | } catch(e) { 98 | done(e); 99 | } 100 | }); 101 | }; 102 | 103 | 104 | /** 105 | * Expose `Strategy`. 106 | */ 107 | module.exports.Strategy = Strategy; 108 | -------------------------------------------------------------------------------- /oauth-config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | provider: { 5 | protocol: "http", 6 | host: "local.foobar3000.com:3001", 7 | profileUrl: "/api/userinfo" 8 | }, 9 | consumer: { 10 | protocol: "http", 11 | host: "local.helloworld3000.com:3002" 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /oauth-consumer-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Example Consumer App' 3 | , icon: 'http://example.com/icon_64.png' 4 | , clientId: 'ward-steward-2' 5 | , clientSecret: 'something truly secret' 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ward-steward", 3 | "version": "0.1.0", 4 | "description": "A Tool for YSA wards to track home and visiting teaching", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": "", 10 | "author": "AJ ONeal (http://coolaj86.com)", 11 | "license": "Apache2", 12 | "dependencies": { 13 | "passport-http-bearer": "~1.0.1", 14 | "connect": "~2.12.0", 15 | "connect_router": "~1.8.7", 16 | "passport": "~0.1.17", 17 | "passport-oauth": "~1.0.0", 18 | "passport-ldsauth": "~0.9.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /passport-example/profile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.parse = function (json) { 4 | var profile = {} 5 | ; 6 | 7 | profile.id = json.currentUserId; 8 | /* 9 | profile.id = json.identity.id; 10 | profile.displayName = json.identity.first_name + ' ' + json.identity.last_name; 11 | profile.name = { familyName: json.identity.last_name, 12 | givenName: json.identity.first_name }; 13 | profile.emails = [{ value: json.identity.email_address }]; 14 | */ 15 | 16 | return profile; 17 | }; 18 | -------------------------------------------------------------------------------- /passport-example/strategy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | var util = require('util') 7 | , OAuth2Strategy = require('passport-oauth').OAuth2Strategy 8 | , InternalOAuthError = require('passport-oauth').InternalOAuthError 9 | , parse = require('./profile').parse 10 | // XXX note that this should have its own config, 11 | // but for simplicity I'm using the main one, one directory up 12 | , pConf = require('../oauth-config').provider 13 | ; 14 | 15 | /** 16 | * `Strategy` constructor. 17 | * 18 | * The example-oauth2orize authentication strategy authenticates requests by delegating to 19 | * example-oauth2orize using the OAuth 2.0 protocol. 20 | * 21 | * Applications must supply a `verify` callback which accepts an `accessToken`, 22 | * `refreshToken` and service-specific `profile`, and then calls the `done` 23 | * callback supplying a `user`, which should be set to `false` if the 24 | * credentials are not valid. If an exception occured, `err` should be set. 25 | * 26 | * Options: 27 | * - `clientID` your example-oauth2orize application's client id 28 | * - `clientSecret` your example-oauth2orize application's client secret 29 | * - `callbackURL` URL to which example-oauth2orize will redirect the user after granting authorization 30 | * 31 | * Examples: 32 | * 33 | * passport.use(new ExampleStrategy({ 34 | * clientID: '123-456-789', 35 | * clientSecret: 'shhh-its-a-secret' 36 | * callbackURL: 'https://www.example.net/auth/example-oauth2orize/callback' 37 | * }, 38 | * function (accessToken, refreshToken, profile, done) { 39 | * User.findOrCreate(..., function (err, user) { 40 | * done(err, user); 41 | * }); 42 | * } 43 | * )); 44 | * 45 | * @param {Object} options 46 | * @param {Function} verify 47 | * @api public 48 | */ 49 | function Strategy(options, verify) { 50 | var me = this 51 | ; 52 | 53 | options = options || {}; 54 | options.authorizationURL = 55 | options.authorizationURL || 56 | options.authorizationUrl || 57 | (pConf.protocol + '://' + pConf.host + '/dialog/authorize') 58 | ; 59 | options.tokenURL = 60 | options.tokenURL || 61 | options.tokenUrl || 62 | (pConf.protocol + '://' + pConf.host + '/oauth/token') 63 | ; 64 | 65 | OAuth2Strategy.call(me, options, verify); 66 | 67 | // must be called after prototype is modified 68 | me.name = 'exampleauth'; 69 | } 70 | 71 | /** 72 | * Inherit from `OAuth2Strategy`. 73 | */ 74 | util.inherits(Strategy, OAuth2Strategy); 75 | 76 | 77 | /** 78 | * Retrieve user profile from example-oauth2orize. 79 | * 80 | * This function constructs a normalized profile, with the following properties: 81 | * 82 | * - `provider` always set to `example-oauth2orize` 83 | * - `id` 84 | * - `username` 85 | * - `displayName` 86 | * 87 | * @param {String} accessToken 88 | * @param {Function} done 89 | * @api protected 90 | */ 91 | Strategy.prototype.userProfile = function (accessToken, done) { 92 | var me = this 93 | ; 94 | 95 | me._oauth2.get( 96 | pConf.protocol + '://' + pConf.host + pConf.profileUrl 97 | , accessToken 98 | , function (err, body/*, res*/) { 99 | var json 100 | , profile 101 | ; 102 | 103 | if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); } 104 | 105 | if ('string' === typeof body) { 106 | try { json = JSON.parse(body); } 107 | catch(e) { done(e); return; } 108 | } else if ('object' === typeof body) { 109 | json = body; 110 | } 111 | 112 | profile = parse(json); 113 | profile.provider = me.name; 114 | profile._raw = body; 115 | profile._json = json; 116 | 117 | done(null, profile); 118 | } 119 | ); 120 | }; 121 | 122 | 123 | /** 124 | * Expose `Strategy`. 125 | */ 126 | module.exports.Strategy = Strategy.Strategy = Strategy; 127 | -------------------------------------------------------------------------------- /public/error.jade: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | body 4 | p You must be Michael Jackson... because you're Bad! No Cookie for you! 5 | -------------------------------------------------------------------------------- /public/index.jade: -------------------------------------------------------------------------------- 1 | doctype 2 | html 3 | head 4 | body 5 | h3 Test OAuth2 Connect 6 | a(href="/auth/example-oauth2orize", target="example_oauth2orize") Connect with example-oauth2orize 7 | -------------------------------------------------------------------------------- /public/success.jade: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | body 4 | h3 Try a protected resource 5 | a(href="/externalapi/account") /externalapi/account 6 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var connect = require('connect') 5 | , path = require('path') 6 | , passport = require('passport') 7 | , User = require('./user') 8 | , ExampleStrategy = require('./passport-example/strategy').Strategy 9 | , app = connect() 10 | , server 11 | , port = process.argv[2] || 3002 12 | , oauthConfig = require('./oauth-config') 13 | , pConf = oauthConfig.provider 14 | , lConf = oauthConfig.consumer 15 | // for Ward Steward 16 | , opts = require('./oauth-consumer-config') 17 | ; 18 | 19 | if (!connect.router) { 20 | connect.router = require('connect_router'); 21 | } 22 | 23 | // Passport session setup. 24 | // To support persistent login sessions, Passport needs to be able to 25 | // serialize users into and deserialize users out of the session. Typically, 26 | // this will be as simple as storing the user ID when serializing, and finding 27 | // the user by ID when deserializing. However, since this example does not 28 | // have a database of user records, the complete Facebook profile is serialized 29 | // and deserialized. 30 | passport.serializeUser(function(user, done) { 31 | //Users.create(user); 32 | done(null, user); 33 | }); 34 | 35 | passport.deserializeUser(function(obj, done) { 36 | var user = obj // Users.read(obj) 37 | ; 38 | 39 | done(null, user); 40 | }); 41 | 42 | passport.use(new ExampleStrategy({ 43 | // see https://github.com/jaredhanson/oauth2orize/blob/master/examples/all-grants/db/clients.js 44 | clientID: opts.clientId 45 | , clientSecret: opts.clientSecret 46 | , callbackURL: lConf.protocol + "://" + lConf.host + "/auth/example-oauth2orize/callback" 47 | } 48 | , function (accessToken, refreshToken, profile, done) { 49 | User.findOrCreate({ profile: profile }, function (err, user) { 50 | user.accessToken = accessToken; 51 | return done(err, user); 52 | }); 53 | } 54 | )); 55 | 56 | function route(rest) { 57 | rest.get('/externalapi/account', function (req, res, next) { 58 | console.log('[using accessToken]', req.user.accessToken); 59 | if (false) { next(); } 60 | var request = require('request') 61 | , options = { 62 | url: pConf.protocol + '://' + pConf.host + '/api/exampleauth/me' 63 | , headers: { 64 | 'Authorization': 'Bearer ' + req.user.accessToken 65 | } 66 | } 67 | ; 68 | 69 | function callback(error, response, body) { 70 | if (!error && response.statusCode === 200) { 71 | res.end(body); 72 | } else { 73 | res.end('error: \n' + body); 74 | } 75 | } 76 | 77 | request(options, callback); 78 | }); 79 | /* 80 | */ 81 | rest.get('/auth/example-oauth2orize', passport.authenticate('exampleauth', { scope: ['email'] })); 82 | rest.get('/auth/example-oauth2orize/callback' 83 | //passport.authenticate('facebook', { successRedirect: '/close.html?accessToken=blar', 84 | // failureRedirect: '/close.html?error=foo' })); 85 | , passport.authenticate('exampleauth', { failureRedirect: '/close.html?error=foo' }) 86 | ); 87 | rest.get('/auth/example-oauth2orize/callback' 88 | , function (req, res) { 89 | console.log('req.session'); 90 | console.log(req.session); 91 | var url = '/success.html' // + '?type=fb' 92 | /* 93 | + '&accessToken=' + req.session.passport.user.accessToken 94 | + '&email=' + req.session.passport.user.profile.email 95 | + '&link=' + req.session.passport.user.profile.profileUrl 96 | */ 97 | ; 98 | 99 | console.log(url); 100 | res.statusCode = 302; 101 | res.setHeader('Location', url); 102 | res.end('hello'); 103 | // This will pass through to the static module 104 | //req.url = url; 105 | //next(); 106 | } 107 | ); 108 | rest.post('/auth/example-oauth2orize/callback', function (req, res/*, next*/) { 109 | console.log('req.user', req.user); 110 | res.end('thanks for playing'); 111 | }); 112 | } 113 | 114 | app 115 | .use(connect.query()) 116 | .use(connect.json()) 117 | .use(connect.urlencoded()) 118 | .use(connect.compress()) 119 | .use(connect.cookieParser()) 120 | .use(connect.session({ secret: 'keyboard mouse' })) 121 | .use(passport.initialize()) 122 | .use(passport.session()) 123 | .use(connect.router(route)) 124 | .use(connect.static(path.join(__dirname, 'public'))) 125 | ; 126 | 127 | module.exports = app; 128 | 129 | if (require.main === module) { 130 | server = app.listen(port, function () { 131 | console.log('Listening on', server.address()); 132 | }); 133 | } 134 | }()); 135 | -------------------------------------------------------------------------------- /user.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | //var cache = {}; 5 | 6 | module.exports.findOrCreate = function (profile, cb) { 7 | console.log('findOrCreate profile', profile); 8 | cb(null, profile); 9 | }; 10 | }()); 11 | --------------------------------------------------------------------------------