Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 7c9d9baefb7e4052b3806448f00de9bd347761ab 0 parents
@jaredhanson authored
2  .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+node_modules
8 .npmignore
@@ -0,0 +1,8 @@
+*.md
+.DS_Store
+.git*
+Makefile
+docs/
+examples/
+support/
+test/
20 LICENSE
@@ -0,0 +1,20 @@
+(The MIT License)
+
+Copyright (c) 2011 Jared Hanson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 Makefile
@@ -0,0 +1,19 @@
+NODE = node
+TEST = ./node_modules/.bin/vows
+TESTS ?= test/*-test.js
+
+test:
+ @NODE_ENV=test NODE_PATH=lib $(TEST) $(TEST_FLAGS) $(TESTS)
+
+docs: docs/api.html
+
+docs/api.html: lib/passport-google-oauth/*.js
+ dox \
+ --title Passport-Google-OAuth \
+ --desc "Google (OAuth 1.0 and OAuth 2.0) authentication strategies for Passport" \
+ $(shell find lib/passport-google-oauth/* -type f) > $@
+
+docclean:
+ rm -f docs/*.{1,html}
+
+.PHONY: test docs docclean
31 README.md
@@ -0,0 +1,31 @@
+# Passport-Google-OAuth
+
+[Passport](https://github.com/jaredhanson/passport) strategies for
+authenticating with Google using OAuth 1.0a and OAuth 2.0.
+
+## Credits
+
+ - [Jared Hanson](http://github.com/jaredhanson)
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 Jared Hanson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
122 examples/oauth/app.js
@@ -0,0 +1,122 @@
+var express = require('express')
+ , passport = require('passport')
+ , util = require('util')
+ , GoogleStrategy = require('passport-google-oauth').OAuthStrategy;
+
+var GOOGLE_CONSUMER_KEY = "--insert-google-consumer-key-here--"
+var GOOGLE_CONSUMER_SECRET = "--insert-google-consumer-secret-here--";
+
+
+// Passport session setup.
+// To support persistent login sessions, Passport needs to be able to
+// serialize users into and deserialize users out of the session. Typically,
+// this will be as simple as storing the user ID when serializing, and finding
+// the user by ID when deserializing. However, since this example does not
+// have a database of user records, the complete Google profile is
+// serialized and deserialized.
+passport.serializeUser(function(user, done) {
+ done(null, user);
+});
+
+passport.deserializeUser(function(obj, done) {
+ done(null, obj);
+});
+
+
+// Use the GoogleStrategy within Passport.
+// Strategies in passport require a `verify` function, which accept
+// credentials (in this case, a token, tokenSecret, and Google profile), and
+// invoke a callback with a user object.
+passport.use(new GoogleStrategy({
+ consumerKey: GOOGLE_CONSUMER_KEY,
+ consumerSecret: GOOGLE_CONSUMER_SECRET,
+ callbackURL: "http://127.0.0.1:3000/auth/google/callback"
+ },
+ function(token, tokenSecret, profile, done) {
+ // asynchronous verification, for effect...
+ process.nextTick(function () {
+
+ // To keep the example simple, the user's Google profile is returned to
+ // represent the logged-in user. In a typical application, you would want
+ // to associate the Google account with a user record in your database,
+ // and return that user instead.
+ return done(null, profile);
+ });
+ }
+));
+
+
+
+
+var app = express.createServer();
+
+// configure Express
+app.configure(function() {
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'ejs');
+ app.use(express.logger());
+ app.use(express.cookieParser());
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(express.session({ secret: 'keyboard cat' }));
+ // Initialize Passport! Also use passport.session() middleware, to support
+ // persistent login sessions (recommended).
+ app.use(passport.initialize());
+ app.use(passport.session());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+});
+
+
+app.get('/', function(req, res){
+ res.render('index', { user: req.user });
+});
+
+app.get('/account', ensureAuthenticated, function(req, res){
+ res.render('account', { user: req.user });
+});
+
+app.get('/login', function(req, res){
+ res.render('login', { user: req.user });
+});
+
+// GET /auth/google
+// Use passport.authenticate() as route middleware to authenticate the
+// request. The first step in Google authentication will involve redirecting
+// the user to google.com. After authorization, Google will redirect the user
+// back to this application at /auth/google/callback
+app.get('/auth/google',
+ passport.authenticate('google', { scope: 'https://www.google.com/m8/feeds' }),
+ function(req, res){
+ // The request will be redirected to Google for authentication, so this
+ // function will not be called.
+ });
+
+// GET /auth/google/callback
+// Use passport.authenticate() as route middleware to authenticate the
+// request. If authentication fails, the user will be redirected back to the
+// login page. Otherwise, the primary route function function will be called,
+// which, in this example, will redirect the user to the home page.
+app.get('/auth/google/callback',
+ passport.authenticate('google', { failureRedirect: '/login' }),
+ function(req, res) {
+ res.redirect('/');
+ });
+
+app.get('/logout', function(req, res){
+ req.logout();
+ res.redirect('/');
+});
+
+app.listen(3000);
+
+
+// Simple route middleware to ensure user is authenticated.
+// Use this route middleware on any resource that needs to be protected. If
+// the request is authenticated (typically via a persistent login session),
+// the request will proceed. Otherwise, the user will be redirected to the
+// login page.
+function ensureAuthenticated(req, res, next) {
+ if (req.isAuthenticated()) { return next(); }
+ res.redirect('/login')
+}
10 examples/oauth/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "passport-google-oauth-examples-oauth",
+ "version": "0.0.0",
+ "dependencies": {
+ "express": ">= 0.0.0",
+ "ejs": ">= 0.0.0",
+ "passport": ">= 0.0.0",
+ "passport-google-oauth": ">= 0.0.0"
+ }
+}
2  examples/oauth/views/account.ejs
@@ -0,0 +1,2 @@
+<p>ID: <%= user.id %></p>
+<p>Name: <%= user.displayName %></p>
5 examples/oauth/views/index.ejs
@@ -0,0 +1,5 @@
+<% if (!user) { %>
+ <h2>Welcome! Please log in.</h2>
+<% } else { %>
+ <h2>Hello, <%= user.displayName %>.</h2>
+<% } %>
21 examples/oauth/views/layout.ejs
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Passport-Google (OAuth) Example</title>
+ </head>
+ <body>
+ <% if (!user) { %>
+ <p>
+ <a href="/">Home</a> |
+ <a href="/login">Log In</a>
+ </p>
+ <% } else { %>
+ <p>
+ <a href="/">Home</a> |
+ <a href="/account">Account</a> |
+ <a href="/logout">Log Out</a>
+ </p>
+ <% } %>
+ <%- body %>
+ </body>
+</html>
1  examples/oauth/views/login.ejs
@@ -0,0 +1 @@
+<a href="/auth/google">Login with Google</a>
123 examples/oauth2/app.js
@@ -0,0 +1,123 @@
+var express = require('express')
+ , passport = require('passport')
+ , util = require('util')
+ , GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
+
+var GOOGLE_CLIENT_ID = "--insert-google-client-id-here--"
+var GOOGLE_CLIENT_SECRET = "--insert-google-client-secret-here--";
+
+
+// Passport session setup.
+// To support persistent login sessions, Passport needs to be able to
+// serialize users into and deserialize users out of the session. Typically,
+// this will be as simple as storing the user ID when serializing, and finding
+// the user by ID when deserializing. However, since this example does not
+// have a database of user records, the complete Google profile is
+// serialized and deserialized.
+passport.serializeUser(function(user, done) {
+ done(null, user);
+});
+
+passport.deserializeUser(function(obj, done) {
+ done(null, obj);
+});
+
+
+// Use the GoogleStrategy within Passport.
+// Strategies in Passport require a `verify` function, which accept
+// credentials (in this case, an accessToken, refreshToken, and Google
+// profile), and invoke a callback with a user object.
+passport.use(new GoogleStrategy({
+ clientID: GOOGLE_CLIENT_ID,
+ clientSecret: GOOGLE_CLIENT_SECRET,
+ callbackURL: "http://127.0.0.1:3000/auth/google/callback"
+ },
+ function(accessToken, refreshToken, profile, done) {
+ // asynchronous verification, for effect...
+ process.nextTick(function () {
+
+ // To keep the example simple, the user's Google profile is returned to
+ // represent the logged-in user. In a typical application, you would want
+ // to associate the Google account with a user record in your database,
+ // and return that user instead.
+ return done(null, profile);
+ });
+ }
+));
+
+
+
+
+var app = express.createServer();
+
+// configure Express
+app.configure(function() {
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'ejs');
+ app.use(express.logger());
+ app.use(express.cookieParser());
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(express.session({ secret: 'keyboard cat' }));
+ // Initialize Passport! Also use passport.session() middleware, to support
+ // persistent login sessions (recommended).
+ app.use(passport.initialize());
+ app.use(passport.session());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+});
+
+
+app.get('/', function(req, res){
+ res.render('index', { user: req.user });
+});
+
+app.get('/account', ensureAuthenticated, function(req, res){
+ res.render('account', { user: req.user });
+});
+
+app.get('/login', function(req, res){
+ res.render('login', { user: req.user });
+});
+
+// GET /auth/google
+// Use passport.authenticate() as route middleware to authenticate the
+// request. The first step in Google authentication will involve
+// redirecting the user to google.com. After authorization, Google
+// will redirect the user back to this application at /auth/google/callback
+app.get('/auth/google',
+ passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile',
+ 'https://www.googleapis.com/auth/userinfo.email'] }),
+ function(req, res){
+ // The request will be redirected to Google for authentication, so this
+ // function will not be called.
+ });
+
+// GET /auth/google/callback
+// Use passport.authenticate() as route middleware to authenticate the
+// request. If authentication fails, the user will be redirected back to the
+// login page. Otherwise, the primary route function function will be called,
+// which, in this example, will redirect the user to the home page.
+app.get('/auth/google/callback',
+ passport.authenticate('google', { failureRedirect: '/login' }),
+ function(req, res) {
+ res.redirect('/');
+ });
+
+app.get('/logout', function(req, res){
+ req.logout();
+ res.redirect('/');
+});
+
+app.listen(3000);
+
+
+// Simple route middleware to ensure user is authenticated.
+// Use this route middleware on any resource that needs to be protected. If
+// the request is authenticated (typically via a persistent login session),
+// the request will proceed. Otherwise, the user will be redirected to the
+// login page.
+function ensureAuthenticated(req, res, next) {
+ if (req.isAuthenticated()) { return next(); }
+ res.redirect('/login')
+}
10 examples/oauth2/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "passport-google-oauth-examples-oauth2",
+ "version": "0.0.0",
+ "dependencies": {
+ "express": ">= 0.0.0",
+ "ejs": ">= 0.0.0",
+ "passport": ">= 0.0.0",
+ "passport-google-oauth": ">= 0.0.0"
+ }
+}
2  examples/oauth2/views/account.ejs
@@ -0,0 +1,2 @@
+<p>ID: <%= user.id %></p>
+<p>Name: <%= user.displayName %></p>
5 examples/oauth2/views/index.ejs
@@ -0,0 +1,5 @@
+<% if (!user) { %>
+ <h2>Welcome! Please log in.</h2>
+<% } else { %>
+ <h2>Hello, <%= user.displayName %>.</h2>
+<% } %>
21 examples/oauth2/views/layout.ejs
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Passport-Google (OAuth 2.0) Example</title>
+ </head>
+ <body>
+ <% if (!user) { %>
+ <p>
+ <a href="/">Home</a> |
+ <a href="/login">Log In</a>
+ </p>
+ <% } else { %>
+ <p>
+ <a href="/">Home</a> |
+ <a href="/account">Account</a> |
+ <a href="/logout">Log Out</a>
+ </p>
+ <% } %>
+ <%- body %>
+ </body>
+</html>
1  examples/oauth2/views/login.ejs
@@ -0,0 +1 @@
+<a href="/auth/google">Login with Google</a>
18 lib/passport-google-oauth/index.js
@@ -0,0 +1,18 @@
+/**
+ * Module dependencies.
+ */
+var OAuthStrategy = require('./oauth');
+var OAuth2Strategy = require('./oauth2');
+
+
+/**
+ * Framework version.
+ */
+require('pkginfo')(module, 'version');
+
+/**
+ * Expose constructors.
+ */
+exports.Strategy =
+exports.OAuthStrategy = OAuthStrategy;
+exports.OAuth2Strategy = OAuth2Strategy;
106 lib/passport-google-oauth/oauth.js
@@ -0,0 +1,106 @@
+/**
+ * Module dependencies.
+ */
+var util = require('util')
+ , OAuthStrategy = require('passport-oauth').OAuthStrategy;
+
+
+/**
+ * `Strategy` constructor.
+ *
+ * The Google authentication strategy authenticates requests by delegating to
+ * Google using the OAuth protocol.
+ *
+ * Applications must supply a `verify` callback which accepts a `token`,
+ * `tokenSecret` and service-specific `profile`, and then calls the `done`
+ * callback supplying a `user`, which should be set to `false` if the
+ * credentials are not valid. If an exception occured, `err` should be set.
+ *
+ * Options:
+ * - `consumerKey` identifies client to Google
+ * - `consumerSecret` secret used to establish ownership of the consumer key
+ * - `callbackURL` URL to which Google will redirect the user after obtaining authorization
+ *
+ * Examples:
+ *
+ * passport.use(new GoogleStrategy({
+ * consumerKey: '123-456-789',
+ * consumerSecret: 'shhh-its-a-secret'
+ * callbackURL: 'https://www.example.net/auth/google/callback'
+ * },
+ * function(token, tokenSecret, profile, done) {
+ * User.findOrCreate(..., function (err, user) {
+ * done(err, user);
+ * });
+ * }
+ * ));
+ *
+ * @param {Object} options
+ * @param {Function} verify
+ * @api public
+ */
+function Strategy(options, verify) {
+ options = options || {};
+ options.requestTokenURL = options.requestTokenURL || 'https://www.google.com/accounts/OAuthGetRequestToken';
+ options.accessTokenURL = options.accessTokenURL || 'https://www.google.com/accounts/OAuthGetAccessToken';
+ options.userAuthorizationURL = options.userAuthorizationURL || 'https://www.google.com/accounts/OAuthAuthorizeToken';
+ options.sessionKey = options.sessionKey || 'oauth:google';
+
+ OAuthStrategy.call(this, options, verify);
+ this.name = 'google';
+}
+
+/**
+ * Inherit from `OAuthStrategy`.
+ */
+util.inherits(Strategy, OAuthStrategy);
+
+/**
+ * Retrieve user profile from Google.
+ *
+ * This function constructs a normalized profile, with the following properties:
+ *
+ * - `id`
+ * - `displayName`
+ *
+ * @param {String} token
+ * @param {String} tokenSecret
+ * @param {Object} params
+ * @param {Function} done
+ * @api protected
+ */
+Strategy.prototype.userProfile = function(token, tokenSecret, params, done) {
+ this._oauth.get('https://www.google.com/m8/feeds/contacts/default/full?max-results=1&alt=json', token, tokenSecret, function (err, body, res) {
+ if (err) { return done(err); }
+
+ try {
+ var json = JSON.parse(body);
+
+ var profile = { provider: 'google' };
+ profile.id = json.feed.id['$t']
+ profile.displayName = json.feed.author[0].name['$t'];
+ profile.emails = [{ value: json.feed.author[0].email['$t'] }];
+
+ done(null, profile);
+ } catch(e) {
+ done(e);
+ }
+ });
+}
+
+Strategy.prototype.requestTokenParams = function(options) {
+ var params = options || {};
+
+ var scope = options.scope;
+ if (scope) {
+ if (Array.isArray(scope)) { scope = scope.join(' '); }
+ params['scope'] = scope;
+ }
+ return params;
+}
+
+
+/**
+ * Expose `Strategy`.
+ */
+module.exports = Strategy;
96 lib/passport-google-oauth/oauth2.js
@@ -0,0 +1,96 @@
+/**
+ * Module dependencies.
+ */
+var util = require('util')
+ , OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
+
+
+/**
+ * `Strategy` constructor.
+ *
+ * The Google authentication strategy authenticates requests by delegating to
+ * Google using the OAuth 2.0 protocol.
+ *
+ * Applications must supply a `verify` callback which accepts an `accessToken`,
+ * `refreshToken` and service-specific `profile`, and then calls the `done`
+ * callback supplying a `user`, which should be set to `false` if the
+ * credentials are not valid. If an exception occured, `err` should be set.
+ *
+ * Options:
+ * - `clientID` your Google application's client id
+ * - `clientSecret` your Google application's client secret
+ * - `callbackURL` URL to which Google will redirect the user after granting authorization
+ *
+ * Examples:
+ *
+ * passport.use(new GoogleStrategy({
+ * clientID: '123-456-789',
+ * clientSecret: 'shhh-its-a-secret'
+ * callbackURL: 'https://www.example.net/auth/google/callback'
+ * },
+ * function(accessToken, refreshToken, profile, done) {
+ * User.findOrCreate(..., function (err, user) {
+ * done(err, user);
+ * });
+ * }
+ * ));
+ *
+ * @param {Object} options
+ * @param {Function} verify
+ * @api public
+ */
+function Strategy(options, verify) {
+ options = options || {};
+ options.authorizationURL = options.authorizationURL || 'https://accounts.google.com/o/oauth2/auth';
+ options.tokenURL = options.tokenURL || 'https://accounts.google.com/o/oauth2/token';
+
+ OAuth2Strategy.call(this, options, verify);
+ this.name = 'google';
+}
+
+/**
+ * Inherit from `OAuth2Strategy`.
+ */
+util.inherits(Strategy, OAuth2Strategy);
+
+
+/**
+ * Retrieve user profile from Google.
+ *
+ * This function constructs a normalized profile, with the following properties:
+ *
+ * - `provider` always set to `google`
+ * - `id`
+ * - `username`
+ * - `displayName`
+ *
+ * @param {String} accessToken
+ * @param {Function} done
+ * @api protected
+ */
+Strategy.prototype.userProfile = function(accessToken, done) {
+ this._oauth2.get('https://www.googleapis.com/oauth2/v1/userinfo', accessToken, function (err, body, res) {
+ if (err) { return done(err); }
+
+ try {
+ var json = JSON.parse(body);
+
+ var profile = { provider: 'google' };
+ profile.id = json.id;
+ profile.displayName = json.name;
+ profile.name = { familyName: json.family_name,
+ givenName: json.given_name };
+ profile.emails = [{ value: json.email }];
+
+ done(null, profile);
+ } catch(e) {
+ done(e);
+ }
+ });
+}
+
+
+/**
+ * Expose `Strategy`.
+ */
+module.exports = Strategy;
27 package.json
@@ -0,0 +1,27 @@
+{
+ "name": "passport-google-oauth",
+ "version": "0.1.0",
+ "description": "Google (OAuth 1.0 and OAuth 2.0) authentication strategies for Passport.",
+ "author": { "name": "Jared Hanson", "email": "jaredhanson@gmail.com", "url": "http://www.jaredhanson.net/" },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/jaredhanson/passport-google-oauth.git"
+ },
+ "bugs": {
+ "url": "http://github.com/jaredhanson/passport-google-oauth/issues"
+ },
+ "main": "./lib/passport-google-oauth",
+ "dependencies": {
+ "pkginfo": "0.2.x",
+ "passport-oauth": "~0.1.3"
+ },
+ "devDependencies": {
+ "vows": "0.6.x"
+ },
+ "engines": { "node": ">= 0.4.0" },
+ "licenses": [ {
+ "type": "MIT",
+ "url": "http://www.opensource.org/licenses/MIT"
+ } ],
+ "keywords": ["passport", "google", "auth", "authn", "authentication", "identity"]
+}
23 test/index-test.js
@@ -0,0 +1,23 @@
+var vows = require('vows');
+var assert = require('assert');
+var util = require('util');
+var google = require('passport-google-oauth');
+
+
+vows.describe('passport-google-oauth').addBatch({
+
+ 'module': {
+ 'should report a version': function (x) {
+ assert.isString(google.version);
+ },
+ 'should export OAuth strategy': function (x) {
+ assert.isFunction(google.Strategy);
+ assert.isFunction(google.OAuthStrategy);
+ assert.equal(google.Strategy, google.OAuthStrategy);
+ },
+ 'should export OAuth 2.0 strategy': function (x) {
+ assert.isFunction(google.OAuth2Strategy);
+ },
+ },
+
+}).export(module);
102 test/oauth-test.js
@@ -0,0 +1,102 @@
+var vows = require('vows');
+var assert = require('assert');
+var util = require('util');
+var GoogleStrategy = require('passport-google-oauth/oauth');
+
+
+vows.describe('GoogleStrategy').addBatch({
+
+ 'strategy': {
+ topic: function() {
+ return new GoogleStrategy({
+ consumerKey: 'ABC123',
+ consumerSecret: 'secret'
+ },
+ function() {});
+ },
+
+ 'should be named google': function (strategy) {
+ assert.equal(strategy.name, 'google');
+ },
+ },
+
+ 'strategy when loading user profile': {
+ topic: function() {
+ var strategy = new GoogleStrategy({
+ consumerKey: 'ABC123',
+ consumerSecret: 'secret'
+ },
+ function() {});
+
+ // mock
+ strategy._oauth.get = function(url, token, tokenSecret, callback) {
+ var body = '{"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gContact":"http://schemas.google.com/contact/2008","xmlns$batch":"http://schemas.google.com/gdata/batch","xmlns$gd":"http://schemas.google.com/g/2005","id":{"$t":"example@gmail.com"},"updated":{"$t":"2012-01-10T19:21:31.537Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/contact/2008#contact"}],"title":{"type":"text","$t":"Jared Hanson\'s Contacts"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/"},{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full"},{"rel":"http://schemas.google.com/g/2005#post","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full"},{"rel":"http://schemas.google.com/g/2005#batch","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full/batch"},{"rel":"self","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full?alt\\u003djson\\u0026max-results\\u003d1"},{"rel":"next","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full?alt\\u003djson\\u0026start-index\\u003d2\\u0026max-results\\u003d1"}],"author":[{"name":{"$t":"Jared Hanson"},"email":{"$t":"example@gmail.com"}}],"generator":{"version":"1.0","uri":"http://www.google.com/m8/feeds","$t":"Contacts"},"openSearch$totalResults":{"$t":"3"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"1"},"entry":[{"id":{"$t":"http://www.google.com/m8/feeds/contacts/example%40gmail.com/base/0"},"updated":{"$t":"2009-09-30T01:58:35.769Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/contact/2008#contact"}],"title":{"type":"text","$t":""},"link":[{"rel":"http://schemas.google.com/contacts/2008/rel#edit-photo","type":"image/*","href":"https://www.google.com/m8/feeds/photos/media/example%40gmail.com/0/0XXxxXXxXxXxx0XX0xXxXx"},{"rel":"http://schemas.google.com/contacts/2008/rel#photo","type":"image/*","href":"https://www.google.com/m8/feeds/photos/media/example%40gmail.com/0"},{"rel":"self","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full/0"},{"rel":"edit","type":"application/atom+xml","href":"https://www.google.com/m8/feeds/contacts/example%40gmail.com/full/0/1111111111111000"}],"gd$email":[{"rel":"http://schemas.google.com/g/2005#other","address":"example+other@gmail.com","primary":"true"}]}]}}';
+
+ callback(null, body, undefined);
+ }
+
+ return strategy;
+ },
+
+ 'when told to load user profile': {
+ topic: function(strategy) {
+ var self = this;
+ function done(err, profile) {
+ self.callback(err, profile);
+ }
+
+ process.nextTick(function () {
+ strategy.userProfile('token', 'token-secret', {}, done);
+ });
+ },
+
+ 'should not error' : function(err, req) {
+ assert.isNull(err);
+ },
+ 'should load profile' : function(err, profile) {
+ assert.equal(profile.provider, 'google');
+ assert.equal(profile.id, 'example@gmail.com');
+ assert.equal(profile.displayName, 'Jared Hanson');
+ assert.equal(profile.emails[0].value, 'example@gmail.com');
+ },
+ },
+ },
+
+ 'strategy when loading user profile and encountering an error': {
+ topic: function() {
+ var strategy = new GoogleStrategy({
+ consumerKey: 'ABC123',
+ consumerSecret: 'secret'
+ },
+ function() {});
+
+ // mock
+ strategy._oauth.get = function(url, token, tokenSecret, callback) {
+ callback(new Error('something went wrong'));
+ }
+
+ return strategy;
+ },
+
+ 'when told to load user profile': {
+ topic: function(strategy) {
+ var self = this;
+ function done(err, profile) {
+ self.callback(err, profile);
+ }
+
+ process.nextTick(function () {
+ strategy.userProfile('token', 'token-secret', {}, done);
+ });
+ },
+
+ 'should error' : function(err, req) {
+ assert.isNotNull(err);
+ },
+ 'should not load profile' : function(err, profile) {
+ assert.isUndefined(profile);
+ },
+ },
+ },
+
+}).export(module);
114 test/oauth2-test.js
@@ -0,0 +1,114 @@
+var vows = require('vows');
+var assert = require('assert');
+var util = require('util');
+var GoogleStrategy = require('passport-google-oauth/oauth2');
+
+
+vows.describe('GoogleStrategy').addBatch({
+
+ 'strategy': {
+ topic: function() {
+ return new GoogleStrategy({
+ clientID: 'ABC123',
+ clientSecret: 'secret'
+ },
+ function() {});
+ },
+
+ 'should be named google': function (strategy) {
+ assert.equal(strategy.name, 'google');
+ },
+ },
+
+ 'strategy when loading user profile': {
+ topic: function() {
+ var strategy = new GoogleStrategy({
+ clientID: 'ABC123',
+ clientSecret: 'secret'
+ },
+ function() {});
+
+ // mock
+ strategy._oauth2.get = function(url, accessToken, callback) {
+ var body = '{ \
+ "id": "00000000000000", \
+ "email": "fred.example@gmail.com", \
+ "verified_email": true, \
+ "name": "Fred Example", \
+ "given_name": "Fred", \
+ "family_name": "Example", \
+ "picture": "https://lh5.googleusercontent.com/-2Sv-4bBMLLA/AAAAAAAAAAI/AAAAAAAAABo/bEG4kI2mG0I/photo.jpg", \
+ "gender": "male", \
+ "locale": "en-US" \
+ }';
+
+ callback(null, body, undefined);
+ }
+
+ return strategy;
+ },
+
+ 'when told to load user profile': {
+ topic: function(strategy) {
+ var self = this;
+ function done(err, profile) {
+ self.callback(err, profile);
+ }
+
+ process.nextTick(function () {
+ strategy.userProfile('access-token', done);
+ });
+ },
+
+ 'should not error' : function(err, req) {
+ assert.isNull(err);
+ },
+ 'should load profile' : function(err, profile) {
+ assert.equal(profile.provider, 'google');
+ assert.equal(profile.id, '00000000000000');
+ assert.equal(profile.displayName, 'Fred Example');
+ assert.equal(profile.name.familyName, 'Example');
+ assert.equal(profile.name.givenName, 'Fred');
+ assert.equal(profile.emails[0].value, 'fred.example@gmail.com');
+ },
+ },
+ },
+
+ 'strategy when loading user profile and encountering an error': {
+ topic: function() {
+ var strategy = new GoogleStrategy({
+ clientID: 'ABC123',
+ clientSecret: 'secret'
+ },
+ function() {});
+
+ // mock
+ strategy._oauth2.get = function(url, accessToken, callback) {
+ callback(new Error('something-went-wrong'));
+ }
+
+ return strategy;
+ },
+
+ 'when told to load user profile': {
+ topic: function(strategy) {
+ var self = this;
+ function done(err, profile) {
+ self.callback(err, profile);
+ }
+
+ process.nextTick(function () {
+ strategy.userProfile('access-token', done);
+ });
+ },
+
+ 'should error' : function(err, req) {
+ assert.isNotNull(err);
+ },
+ 'should not load profile' : function(err, profile) {
+ assert.isUndefined(profile);
+ },
+ },
+ },
+
+}).export(module);
Please sign in to comment.
Something went wrong with that request. Please try again.