Skip to content

Commit

Permalink
Sample OAuth2 server supporting refresh token grants.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastián Peyrott committed Oct 7, 2015
0 parents commit 7ec632d
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
db
node_modules
47 changes: 47 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var express = require('express');
var bodyParser = require('body-parser');
var oauthserver = require('oauth2-server');
var mongoose = require('mongoose');
var model = require('./model');

var mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/test';

mongoose.connect(mongoUrl, function (err, res) {
if (err) {
console.log('ERROR connecting to: ' + mongoUrl + '. ' + err);
} else {
console.log('Succeeded connecting to: ' + mongoUrl);
}
});

var app = express();

app.use(bodyParser.urlencoded({ extended: true }));

app.use(bodyParser.json());

app.oauth = oauthserver({
model: model,
grants: ['auth_code', 'password', 'refresh_token'],
debug: true,
accessTokenLifetime: model.accessTokenLifetime
});

// Handle token grant requests
app.all('/oauth/token', app.oauth.grant());

app.get('/secret', app.oauth.authorise(), function (req, res) {
// Will require a valid access_token
res.send('Secret area');
});

app.get('/public', function (req, res) {
// Does not require an access_token
res.send('Public area');
});

// Error handling
app.use(app.oauth.errorHandler());

app.listen(3000);

166 changes: 166 additions & 0 deletions model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* Copyright 2013-present NightWorld.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');

var Schema = mongoose.Schema;
var model = module.exports;

model.accessTokenLifetime = 20;

// JWT secret key
var secretKey = 'sample secret key';

// Mongoose schemas

var OAuthRefreshTokenSchema = new Schema({
refreshToken: { type: String },
clientId: { type: String },
userId: { type: String },
expires: { type: Date }
});

var OAuthClientSchema = new Schema({
clientId: { type: String },
clientSecret: { type: String },
redirectUri: { type: String }
});

var OAuthUserSchema = new Schema({
username: { type: String },
password: { type: String },
firstname: { type: String },
lastname: { type: String },
email: { type: String, default: '' }
});

mongoose.model('OAuthRefreshToken', OAuthRefreshTokenSchema);
mongoose.model('OAuthClient', OAuthClientSchema);
mongoose.model('OAuthUser', OAuthUserSchema);

var OAuthRefreshTokensModel = mongoose.model('OAuthRefreshToken'),
OAuthClientsModel = mongoose.model('OAuthClient'),
OAuthUsersModel = mongoose.model('OAuthUser');

// The following functions customize the behavior of oauth2-server

/* Token functions */
model.getAccessToken = function (bearerToken, callback) {
console.log('in getAccessToken (bearerToken: ' + bearerToken + ')');

try {
var decoded = jwt.verify(bearerToken, secretKey, {
ignoreExpiration: true //handled by OAuth2 server implementation
});
callback(null, {
accessToken: bearerToken,
clientId: decoded.sub,
userId: decoded.user,
expires: new Date(decoded.exp * 1000)
});
} catch(e) {
callback(e);
}
};

model.saveAccessToken = function (token, clientId, expires, userId, callback) {
console.log('in saveAccessToken (token: ' + token +
', clientId: ' + clientId + ', userId: ' + userId.id +
', expires: ' + expires + ')');

//No need to store JWT tokens.
console.log(jwt.decode(token, secretKey));

callback(null);
};

model.generateToken = function(type, req, callback) {
//Use the default implementation for refresh tokens
console.log('generateToken: ' + type);
if(type === 'refreshToken') {
callback(null, null);
return;
}

//Use JWT for access tokens
var token = jwt.sign({
user: req.user.id
}, secretKey, {
expiresIn: model.accessTokenLifetime,
subject: req.client.clientId
});

callback(null, token);
}

model.saveRefreshToken = function (token, clientId, expires, userId, callback) {
console.log('in saveRefreshToken (token: ' + token +
', clientId: ' + clientId +
', userId: ' + userId.id + ', expires: ' + expires + ')');

var refreshToken = new OAuthRefreshTokensModel({
refreshToken: token,
clientId: clientId,
userId: userId.id,
expires: expires
});

refreshToken.save(callback);
};

model.getRefreshToken = function (refreshToken, callback) {
console.log('in getRefreshToken (refreshToken: ' + refreshToken + ')');

OAuthRefreshTokensModel.findOne({ refreshToken: refreshToken }, callback);
};

model.getClient = function (clientId, clientSecret, callback) {
console.log('in getClient (clientId: ' + clientId +
', clientSecret: ' + clientSecret + ')');
if (clientSecret === null) {
return OAuthClientsModel.findOne({ clientId: clientId }, callback);
}
OAuthClientsModel.findOne({
clientId: clientId,
clientSecret: clientSecret
}, callback);
};

model.grantTypeAllowed = function (clientId, grantType, callback) {
console.log('in grantTypeAllowed (clientId: ' + clientId +
', grantType: ' + grantType + ')');

// Authorize all clients to use all grants.
callback(false, true);
};

model.getUser = function (username, password, callback) {
console.log('in getUser (username: ' + username +
', password: ' + password + ')');

OAuthUsersModel.findOne({ username: username, password: password },
function(err, user) {
if(err) return callback(err);
console.log('User id: ' + user._id);
callback(null, user._id);
}
);
};




18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "refresh-tokens-sample",
"version": "1.0.0",
"description": "A simple refresh token issuing server",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "UNLICENSED",
"dependencies": {
"body-parser": "^1.14.1",
"express": "^4.13.3",
"jsonwebtoken": "^5.4.0",
"mongoose": "^4.1.10",
"oauth2-server": "^2.4.1"
}
}

0 comments on commit 7ec632d

Please sign in to comment.