1 | /****************
|
2 | * IMPORTS
|
3 | */
|
4 |
|
5 | var util = require('util')
|
6 | var OAuth2Strategy = require('passport-oauth2')
|
7 | var InternalOAuthError = require('passport-oauth2').InternalOAuthError
|
8 |
|
9 | /**
|
10 | * `Strategy` constructor.
|
11 | *
|
12 | * The Google authentication strategy authenticates requests by delegating to
|
13 | * Google using the OAuth 2.0 protocol.
|
14 | *
|
15 | * Applications must supply a `verify` callback which accepts an `accessToken`,
|
16 | * `refreshToken` and service-specific `profile`, and then calls the `done`
|
17 | * callback supplying a `user`, which should be set to `false` if the
|
18 | * credentials are not valid. If an exception occured, `err` should be set.
|
19 | *
|
20 | * Options:
|
21 | * - `clientId` your Google application's client id
|
22 | * - `clientSecret` your Google application's client secret
|
23 | * - `callbackURL` URL to which Google will redirect the user after granting authorizationin your Google Application
|
24 | *
|
25 | * Examples:
|
26 | *
|
27 | * passport.use(new GoogleDriveStrategy({
|
28 | * clientID: '123-456-789',
|
29 | * clientSecret: 'shhh-its-a-secret'
|
30 | * callbackURL: 'https://www.example.net/auth/google-drive/callback'
|
31 | * },
|
32 | * function(accessToken, refreshToken, profile, done) {
|
33 | * User.findOrCreate(..., function (err, user) {
|
34 | * done(err, user);
|
35 | * });
|
36 | * }
|
37 | * ));
|
38 | *
|
39 | * @param {Object} options
|
40 | * @param {Function} verify
|
41 | * @api public
|
42 | */
|
43 |
|
44 | function GoogleDriveStrategy (options, verify) {
|
45 | options = options || {};
|
46 | options.authorizationURL = options.authorizationURL || 'https://accounts.google.com/o/oauth2/auth'
|
47 | options.tokenURL = options.tokenURL || 'https://accounts.google.com/o/oauth2/token'
|
48 |
|
49 | OAuth2Strategy.call(this, options, verify)
|
50 | this.name = 'google-drive'
|
51 | }
|
52 |
|
53 | /**
|
54 | * Inherit from `OAuth2Strategy`.
|
55 | */
|
56 |
|
57 | util.inherits(GoogleDriveStrategy, OAuth2Strategy)
|
58 |
|
59 | /**
|
60 | * Retrieve user profile from Google Drive.
|
61 | *
|
62 | * This function constructs a normalized profile, with the following properties:
|
63 | *
|
64 | * - `provider` always set to `google-drive`
|
65 | * - `id`
|
66 | * - etc..
|
67 | *
|
68 | * @param {String} accessToken
|
69 | * @param {Function} done
|
70 | * @api protected
|
71 | */
|
72 |
|
73 | GoogleDriveStrategy.prototype.authenticate = function (req, options) {
|
74 | options || (options = {})
|
75 |
|
76 | var oldHint = options.loginHint
|
77 | options.loginHint = req.query.login_hint
|
78 | OAuth2Strategy.prototype.authenticate.call(this, req, options)
|
79 | options.loginHint = oldHint
|
80 | }
|
81 |
|
82 | GoogleDriveStrategy.prototype.userProfile = function (accessToken, done) {
|
83 |
|
84 | this._oauth2.get('https://www.googleapis.com/drive/v2/about', accessToken, function (err, body, res) {
|
85 |
|
86 | if (err) {
|
87 | return done(new InternalOAuthError('failed to fetch user profile', err))
|
88 | }
|
89 | try {
|
90 | var json = JSON.parse(body)
|
91 |
|
92 | var profile = { provider: 'google-drive' }
|
93 | profile.id = 'drive-' + json.user.permissionId
|
94 | profile.displayName = json.user.displayName
|
95 | profile.name = json.name
|
96 |
|
97 | if (json.user.emailAddress) {
|
98 | profile.email = json.user.emailAddress
|
99 | }
|
100 | if (json.user.picture) {
|
101 | profile.picture = json.user.picture.url
|
102 | }
|
103 | profile.quotaBytesTotal = json.quotaBytesTotal || 0
|
104 | profile.quotaBytesUsed = json.quotaBytesUsed || 0
|
105 | profile.quotaBytesUsedAggregate = json.quotaBytesUsedAggregate || 0
|
106 | profile.quotaBytesUsedInTrash = json.quotaBytesUsedInTrash || 0
|
107 | profile.quotaType = json.quotaType || ''
|
108 |
|
109 | profile._raw = body
|
110 | profile._json = json
|
111 |
|
112 | done(null, profile)
|
113 | }
|
114 | catch (e) {
|
115 | done(e)
|
116 | }
|
117 | })
|
118 | }
|
119 |
|
120 | GoogleDriveStrategy.prototype.authorizationParams = function (options) {
|
121 | var params = {}
|
122 | if (options.accessType) {
|
123 | params['access_type'] = options.accessType
|
124 | }
|
125 | if (options.approvalPrompt) {
|
126 | params['approval_prompt'] = options.approvalPrompt
|
127 | }
|
128 | if (options.prompt) {
|
129 | // This parameter is undocumented in Google's official documentation.
|
130 | // However, it was detailed by Breno de Medeiros (who works at Google) in
|
131 | // this Stack Overflow answer:
|
132 | // http://stackoverflow.com/questions/14384354/force-google-account-chooser/14393492#14393492
|
133 | params['prompt'] = options.prompt
|
134 | }
|
135 | if (options.loginHint) {
|
136 | // This parameter is derived from OpenID Connect, and supported by Google's
|
137 | // OAuth 2.0 endpoint.
|
138 | // https://github.com/jaredhanson/passport-google-oauth/pull/8
|
139 | // https://bitbucket.org/openid/connect/commits/970a95b83add
|
140 | params['login_hint'] = options.loginHint
|
141 | }
|
142 | if (options.userID) {
|
143 | // Undocumented, but supported by Google's OAuth 2.0 endpoint. Appears to
|
144 | // be equivalent to `login_hint`.
|
145 | params['user_id'] = options.userID
|
146 | }
|
147 | if (options.hostedDomain || options.hd) {
|
148 | // This parameter is derived from Google's OAuth 1.0 endpoint, and (although
|
149 | // undocumented) is supported by Google's OAuth 2.0 endpoint was well.
|
150 | // https://developers.google.com/accounts/docs/OAuth_ref
|
151 | params['hd'] = options.hostedDomain || options.hd
|
152 | }
|
153 | return params
|
154 | }
|
155 |
|
156 | /**
|
157 | * Expose `Strategy`.
|
158 | */
|
159 |
|
160 | module.exports = GoogleDriveStrategy
|