Skip to content

OAuth2 authorize URL extra params + Google example #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,108 @@ For the Rdio API test, beta access to their new API is necessary.
The site for the beta API is: "http://www.rdio.com/developers/"


---


### Example #5 - Google API config that uses Authorization Code OAuth 2

```js
"google": {
"name": "Google Calendar API (OAuth 2.0 Auth Code)",
"protocol": "https",
"baseURL": "www.googleapis.com",
"publicPath": "/calendar/v3",
"privatePath": "/calendar/v3",
"headers" : {},
"booleanTrueVal": "true",
"booleanFalseVal": "false",
"auth": "oauth2",
"oauth2": {
"type": "authorization-code",
"baseSite": "https://accounts.google.com/",
"authorizeURL": "o/oauth2/auth",
"accessTokenURL": "o/oauth2/token",
"customHeaders": {},
"tokenName": "access_token",
"extraParameters": {"scope": "https://www.googleapis.com/auth/calendar.readonly", "response_type": "code" }
},
"keyParam": ""
},
```

Line:

1. Handle of the API. It is used to pull up the client
interface in the URL:

Ex: http://localhost:3000/google

2. "name" key value is a string that holds the name
of the API that is used in the Jade template output.

3. "protocol" key value contains either *http* or *https*,
but you're welcome to try other protocols.

4. "baseURL" key value is the base URL that accepts
the API calls (should not include protocol)

5. "publicPath" key value is the path prefix prepended
to all method URIs for non-protected method resources.
This value often includes the version in RESTful APIs.

Ex: "/v1", "/1", etc.

6. "privatePath" key value is the path prefix prepended
to all method URIs for OAuth2 protected method resources.
This value is most often the version in RESTful APIs.

Ex: "/v1", "/1", etc.

8. The value to be sent for boolean "True"

9. The value to be sent for boolean "False"

10. "auth" key value is set to "oauth2" when OAuth2 is the
authentication mechanism. Field is required.

11. "oauth" key value is a JSON object that contains the
OAuth implementation details for this API. Field is
required when "auth" value is "oauth".

12. "type" key value is the OAuth 2 authorization flow
used for this API. Valid values are "authorization-code",
"client_credentials", and "implicit", named for each grant
found here: "http://tools.ietf.org/html/rfc6749".

13. "baseSite" key value is the base website URL used in
the OAuth 2 dance. It is required.

14. "authorizeURL" key value is the url string used to
retrieve the authorization token in the
"authorization-code" OAuth 2 flow. This is not necessary
in any other OAuth 2 flow.

15. "accessTokenURL" key value is the url string used to
retrieve the access (Bearer) token in any OAuth 2 flow.
This is required in all OAuth 2 flows.

17. "tokenName" key value if the API does not use "access_token"
as the default token name when making calls with the
access token in the url query parameters. Not required if
"access_token" is used.

18. "extraParameters" lists any parameters that must be included
in the Authorization URL. For instance, Google needs to see
a "scope" parameter in the authorization URL.
Only required if this is the case.

19. Closing curly bracket for "oauth2" JSON object.

20. "keyParam" key value is blank when OAuth 2 is the authentication
method.

21. Closing curly bracket for main object.


API-LEVEL CONFIG DETAILS
========================
Expand Down
62 changes: 51 additions & 11 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ app.configure('production', function() {
// Middleware
//
function oauth(req, res, next) {
console.log('OAuth process started');
if (config.debug) {
console.log('OAuth process started');
};
var apiName = req.body.apiName,
apiConfig = apisConfig[apiName];

Expand Down Expand Up @@ -201,7 +203,9 @@ function oauth(req, res, next) {
}

function oauth2(req, res, next){
console.log('OAuth2 process started');
if (config.debug) {
console.log('OAuth2 process started');
};
var apiName = req.body.apiName,
apiConfig = apisConfig[apiName],
urlp = url.parse(req.originalUrl, true);
Expand All @@ -216,7 +220,8 @@ function oauth2(req, res, next){
apiSecret,
apiConfig.oauth2.baseSite,
apiConfig.oauth2.authorizeURL,
apiConfig.oauth2.accessTokenURL);
apiConfig.oauth2.accessTokenURL,
apiConfig.oauth2.customHeaders );

if (apiConfig.oauth2.tokenName) {
oa.setAccessTokenName(apiConfig.oauth2.tokenName);
Expand All @@ -231,8 +236,15 @@ function oauth2(req, res, next){
};

if (apiConfig.oauth2.type == 'authorization-code') {
var redirectUrl = oa.getAuthorizeUrl({redirect_uri : callbackURL, response_type : 'code'});
var oauth2Params = {redirect_uri : callbackURL, response_type : 'code'};
for( var itemKey in apiConfig.oauth2.extraParameters ) {
oauth2Params[itemKey]= apiConfig.oauth2.extraParameters[itemKey];
};

var redirectUrl = oa.getAuthorizeUrl( oauth2Params );
if (config.debug) {
console.log('OAuth redirectUrl: ' + redirectUrl);
};
db.set(key + ':apiKey', apiKey, redis.print);
db.set(key + ':apiSecret', apiSecret, redis.print);
db.set(key + ':baseURL', req.headers.referer, redis.print);
Expand Down Expand Up @@ -264,7 +276,7 @@ function oauth2(req, res, next){
var accessURL = apiConfig.oauth2.baseSite + apiConfig.oauth2.accessTokenURL;
var basic_cred = apiKey + ':' + apiSecret;
var encoded_basic = new Buffer(basic_cred).toString('base64')

http_method = (apiConfig.oauth2.authorizationHeader == 'Y') ? "POST" : "GET";
header = (apiConfig.oauth2.authorizationHeader == 'Y') ? {'Authorization' : 'Basic ' + encoded_basic} : '';
fillerpost = query.stringify({grant_type : "client_credentials", client_id : apiKey, client_secret : apiSecret});
Expand Down Expand Up @@ -317,7 +329,9 @@ function oauth2(req, res, next){


function oauth2Success(req, res, next) {
console.log('oauth2Success started');
if (config.debug) {
console.log('oauth2Success started');
};
var apiKey,
apiSecret,
apiName = req.params.api,
Expand Down Expand Up @@ -371,8 +385,15 @@ function oauth2Success(req, res, next) {
};

if (apiConfig.oauth2.type == 'authorization-code') {
if (config.debug) {
console.log('inside authorization-code');
console.log('redirect_uri : '+ callbackURL);
console.log('client_id : '+ apiKey);
console.log('client_secret : ' + apiSecret);
};

oa.getOAuthAccessToken(req.query.code,
{grant_type : "authorization_code", redirect_uri : baseURL, client_id : apiKey, client_secret : apiSecret},
{grant_type : "authorization_code", redirect_uri : callbackURL, client_id : apiKey, client_secret : apiSecret},
function(error, oauth2access_token, oauth2refresh_token, results){
if (error) {
res.send("Error getting OAuth access token : " + util.inspect(error) + "["+oauth2access_token+"]"+ "["+oauth2refresh_token+"]", 500);
Expand Down Expand Up @@ -548,13 +569,22 @@ function processRequest(req, res, next) {
path: apiConfig.publicPath + methodURL// + ((paramString.length > 0) ? '?' + paramString : "")
};

if (config.debug) {
console.log('just built privateReqURL');
console.log('apiConfig.baseURL: ' + apiConfig.baseURL);
console.log('apiConfig.privatePath: ' + apiConfig.privatePath);
console.log('methodURL: ' + methodURL);
console.log('paramString: ' + paramString);
};

if (['POST','DELETE','PUT'].indexOf(httpMethod) !== -1) {
var requestBody = query.stringify(params);
}

if (apiConfig.oauth) {
console.log('Using OAuth');

if (config.debug) {
console.log('Using OAuth');
};
// Three legged OAuth
if (apiConfig.oauth.type == 'three-legged' && (reqQuery.oauth == 'authrequired' || (req.session[apiName] && req.session[apiName].authed))) {
if (config.debug) {
Expand Down Expand Up @@ -687,8 +717,9 @@ function processRequest(req, res, next) {
unsecuredCall();
}
} else if (apiConfig.oauth2) {
console.log('Using OAuth2');

if (config.debug) {
console.log('Using OAuth2');
};
if (implicitAccessToken) {
db.mset([key + ':access_token', implicitAccessToken
], function(err, results2) {
Expand Down Expand Up @@ -736,6 +767,15 @@ function processRequest(req, res, next) {
var headers = {Authorization : "Bearer " + access_token};
}

if (config.debug) {
console.log('now calling oa._request with');
console.log('Access token: ' + access_token);
console.log('httpMethod: ' + httpMethod);
console.log('privateReqURL: ' + privateReqURL);
console.log('headers: ' + headers);
console.log('requestBody: ' + requestBody );
};

oa._request(httpMethod, privateReqURL, headers, requestBody, access_token, function (error, data, response) {
req.call = privateReqURL;

Expand Down
22 changes: 22 additions & 0 deletions public/data/apiconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
{
"google": {
"name": "Google Calendar API (OAuth 2.0 Auth Code)",
"protocol": "https",
"baseURL": "www.googleapis.com",
"publicPath": "/calendar/v3",
"privatePath": "/calendar/v3",
"headers" : {},
"booleanTrueVal": "true",
"booleanFalseVal": "false",
"auth": "oauth2",
"oauth2": {
"type": "authorization-code",
"baseSite": "https://accounts.google.com/",
"authorizeURL": "o/oauth2/auth",
"accessTokenURL": "o/oauth2/token",
"customHeaders": {},
"tokenName": "access_token",
"extraParameters": {"scope": "https://www.googleapis.com/auth/calendar.readonly", "response_type": "code" }
},
"keyParam": ""
},

"klout": {
"name": "Klout v2 API",
"protocol": "http",
Expand Down
57 changes: 57 additions & 0 deletions public/data/google.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"endpoints":[
{
"name":"Google Calendar",
"methods":[
{
"MethodName":"CalendarList: list",
"Synopsis":"Returns entries on the user's calendar list",
"HTTPMethod":"GET",
"URI":"/users/me/calendarList",
"RequiresOAuth":"Y",
"parameters":[
{
"Name":"maxResults",
"Required":"N",
"Default":"",
"Type":"int",
"Description":"the maximum number of activity items to be returned"
},
{
"Name":"minAccessRole",
"Required":"N",
"Default":"",
"Type":"enumerated",
"EnumeratedList": [
"freeBusyReader",
"owner",
"reader",
"writer"
],
"EnumeratedDescription": {
"freeBusyReader": "The user can read free/busy information.",
"owner": "The user can read and modify events and access control lists",
"reader": "The user can read events that are not private",
"writer": "The user can read and modify events"
},
"Description":"The minimum access role for the user in the returned entires. Optional. The default is no restriction."
},
{
"Name":"pageToken",
"Required":"N",
"Default":"",
"Type":"string",
"Description":"Token specifying which result page to return"
},
{
"Name":"showHidden",
"Required":"N",
"Type":"boolean",
"Description":"Whether to show hidden entries. default's to False"
}
]
}
]
}
]
}