Skip to content
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
148 changes: 102 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This is a real bummer. So we built Gatekeeper, which is the missing piece you ne
Gatekeeper works well with [Github.js](https://github.com/michael/github), which helps you accessing the [Github API](http://developer.github.com/v3/) from the browser.

## API

```
GET http://localhost:9999/authenticate/TEMPORARY_CODE
```
Expand All @@ -18,21 +18,21 @@ GET http://localhost:9999/authenticate/TEMPORARY_CODE
Also see the [documentation on Github](http://developer.github.com/v3/oauth/).

1. Redirect users to request GitHub access.

```
GET https://github.com/login/oauth/authorize
```

2. GitHub redirects back to your site including a temporary code you need for the next step.

You can grab it like so:

```js
var code = window.location.href.match(/\?code=(.*)/)[1];
```

3. Request the actual token using your instance of Gatekeeper, which knows your `client_secret`.

```js
$.getJSON('http://localhost:9999/authenticate/'+code, function(data) {
console.log(data.token);
Expand All @@ -41,64 +41,120 @@ Also see the [documentation on Github](http://developer.github.com/v3/oauth/).

## Setup your Gatekeeper

1. Clone it
1. Clone it

```
git clone [email protected]:prose/gatekeeper.git
```
```
git clone [email protected]:anvaka/gatekeeper.git
```

2. Install Dependencies

```
cd gatekeeper && npm install
```
2. Install Dependencies

3. Adjust config.json
```
cd gatekeeper && npm install
```

```js
{
"client_id": "GITHUB_APPLICATION_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_CLIENT_SECRET",
"host": "github.com",
"port": 443,
"path": "/login/oauth/access_token",
"method": "POST",
"server": {
"port": 9999
}
}
```
3. Adjust config.json

You can also set environment variables to override the settings if you don't want Git to track your adjusted config.json file. Just use UPPER_CASE keys.
```js
{
"default" : {
"client_id": "GITHUB_APPLICATION_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_CLIENT_SECRET"
},
"oauth_host": "github.com",
"oauth_port": 443,
"oauth_path": "/login/oauth/access_token",
"oauth_method": "POST"
}
```

If you want to support multiple apps (e.g. one for localhost development, one
for beta and one for production), you can adjust your config with use case name:

```js
{
"local": {
"client_id": "GITHUB_APPLICATION_LOCAL_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_LOCAL_CLIENT_SECRET"
},
"beta": {
"client_id": "GITHUB_APPLICATION_BETA_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_BETA_CLIENT_SECRET"
},
"default" : {
"client_id": "GITHUB_APPLICATION_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_CLIENT_SECRET"
},
"oauth_host": "github.com",
"oauth_port": 443,
"oauth_path": "/login/oauth/access_token",
"oauth_method": "POST"
}
```

You can also set environment variables to override the settings if you don't
want Git to track your adjusted config.json file:

``` sh
export BETA='{"client_id": "CLIENT_ID", "client_secret": "CLIENT_SECRET"}'
```

4. Serve it

```
$ node server.js
```
```
$ node server.js
```

## Deploy on Heroku

0. Install [heroku CLI](https://devcenter.heroku.com/articles/heroku-command).
Login to heroku:

```
heroku login
```

1. Create a new Heroku app
```
cake heroku:create
```

```
heroku apps:create
```

2. Rename it (optional)
```
heroku apps:rename NEW_NAME
```

```
heroku apps:rename NEW_NAME
```

3. Provide OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET:

```
cake -c OAUTH_CLIENT_ID -s OAUTH_CLIENT_SECRET heroku:config
```
```
heroku config:set DEFAULT='{"client_id": "CLIENT_ID", "client_secret": "CLIENT_SECRET"}'
```

4. Push changes to heroku

```
cake heroku:push
```
```
git push heroku master
```

5. Verify it is working:

```
curl your_app_name.herokuapp.com/
```

Should return something like `Cannot GET /`

To actually trade github code for an access token call:

```
curl your_app_name.herokuapp.com/authenticate/code
```

If you want to use a particular use case (e.g. beta), declared in your config:

```
curl your_app_name.herokuapp.com/authenticate/code?case=beta
```

12 changes: 9 additions & 3 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
{
"oauth_client_id": "GITHUB_APPLICATION_CLIENT_ID",
"oauth_client_secret": "GITHUB_APPLICATION_CLIENT_SECRET",
"localhost" : {
"client_id": "GITHUB_APPLICATION_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_CLIENT_SECRET"
},
"default" : {
"client_id": "GITHUB_APPLICATION_CLIENT_ID",
"client_secret": "GITHUB_APPLICATION_CLIENT_SECRET"
},
"oauth_host": "github.com",
"oauth_port": 443,
"oauth_path": "/login/oauth/access_token",
"oauth_method": "POST"
}
}
76 changes: 49 additions & 27 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
var url = require('url'),
http = require('http'),
https = require('https'),
fs = require('fs'),
qs = require('querystring'),
express = require('express'),
app = express();
var url = require('url'),
http = require('http'),
https = require('https'),
fs = require('fs'),
qs = require('querystring'),
express = require('express'),
app = express();

// Load config defaults from JSON file.
// Environment variables override defaults.
function loadConfig() {
var config = JSON.parse(fs.readFileSync(__dirname+ '/config.json', 'utf-8'));
for (var i in config) {
config[i] = process.env[i.toUpperCase()] || config[i];
}
var config = require('./config.json');
Object.keys(config).forEach(function(key) {
var envValue = process.env[key.toUpperCase()];
if (!envValue) return;

config[key] = (typeof config[key] === 'object') ? JSON.parse(envValue) : envValue;
});

console.log('Configuration');
console.log(config);
return config;
}

var config = loadConfig();

function authenticate(code, cb) {
function authenticate(code, useCase, cb) {
var oauth = config[useCase] || config.default;

if (!oauth) {
cb(new Error('Could not find oauth settings'), null);
return;
}

var data = qs.stringify({
client_id: config.oauth_client_id,
client_secret: config.oauth_client_secret,
client_id: oauth.client_id,
client_secret: oauth.client_secret,
code: code
});

Expand All @@ -32,44 +43,55 @@ function authenticate(code, cb) {
port: config.oauth_port,
path: config.oauth_path,
method: config.oauth_method,
headers: { 'content-length': data.length }
headers: {
'content-length': data.length
}
};

var body = "";
var req = https.request(reqOptions, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) { body += chunk; });
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
cb(null, qs.parse(body).access_token);
});
});

req.write(data);
req.end();
req.on('error', function(e) { cb(e.message); });
req.on('error', function(e) {
cb(e.message);
});
}


// Convenience for allowing CORS on routes - GET only
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});


app.get('/authenticate/:code', function(req, res) {
console.log('authenticating code:' + req.params.code);
authenticate(req.params.code, function(err, token) {
var result = err || !token ? {"error": "bad_code"} : { "token": token };
console.log(result);
res.json(result);
});
console.log('authenticating code:', req.params.code);
console.log('use case: ', req.query.case);
authenticate(req.params.code, req.query.case, function(err, token) {
var result = err || !token ? {
"error": "bad_code"
} : {
"token": token
};
console.log(result);
res.json(result);
});
});

var port = process.env.PORT || config.port || 9999;

app.listen(port, null, function (err) {
app.listen(port, null, function(err) {
console.log('Gatekeeper, at your service: http://localhost:' + port);
});