Jawbone API OAuth access_token handling with node.js (express & passport) - javascript

Has anyone successfully navigated Jawbone's OAuth2.0 authentication for their REST API?
I am unable to figure out how to access and send the authorization_code in order to obtain the access_token (steps 4 & 5 in the Jawbone API Authorization Documentation). I want to reuse the access_token for subsequent (AJAX-style) calls and avoid asking the user to reauthorize each time.
Each call of the API (get.sleeps) requires a full round trip of the auth process including this reauthorization to get an authorization_token (screen shot). Both the Jawbone and Passport Documentation is vague on this point.
My stack involves, node.js, the jawbone-up NPM, express.js and passport.js. The Passport Strategy for Jawbone appears to work correctly as I get valid data back.
The jawbone-up NPM explicitly does not help maintain the session (access_token), saying "This library does not assist in getting an access_token through OAuth..."
QUESTION: how do I actually use the OAUTH access_token in the API call? Can someone show me some code to do this?
Thanks
var dotenv = require('dotenv').load(),
express = require('express'),
app = express(),
ejs = require('ejs'),
https = require('https'),
fs = require('fs'),
bodyParser = require('body-parser'),
passport = require('passport'),
JawboneStrategy = require('passport-oauth').OAuth2Strategy,
port = 5000,
jawboneAuth = {
clientID: process.env.JAWBONE_CLIENT_ID,
clientSecret: process.env.JAWBONE_CLIENT_SECRET,
authorizationURL: process.env.JAWBONE_AUTH_URL,
tokenURL: process.env.JAWBONE_AUTH_TOKEN_URL,
callbackURL: process.env.JAWBONE_CALLBACK_URL
},
sslOptions = {
key: fs.readFileSync('./server.key'),
cert: fs.readFileSync('./server.crt')
};
app.use(bodyParser.json());
app.use(express.static(__dirname + '/public'));
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
// ----- Passport set up ----- //
app.use(passport.initialize());
app.get('/',
passport.authorize('jawbone', {
scope: ['basic_read','sleep_read'],
failureRedirect: '/'
})
);
app.get('/done',
passport.authorize('jawbone', {
scope: ['basic_read','sleep_read'],
failureRedirect: '/'
}), function(req, res) {
res.render('userdata', req.account);
}
);
passport.use('jawbone', new JawboneStrategy({
clientID: jawboneAuth.clientID,
clientSecret: jawboneAuth.clientSecret,
authorizationURL: jawboneAuth.authorizationURL,
tokenURL: jawboneAuth.tokenURL,
callbackURL: jawboneAuth.callbackURL
}, function(token, refreshToken, profile, done) {
var options = {
access_token: token,
client_id: jawboneAuth.clientID,
client_secret: jawboneAuth.clientSecret
},
up = require('jawbone-up')(options);
up.sleeps.get({}, function(err, body) {
if (err) {
console.log('Error receiving Jawbone UP data');
} else {
var jawboneData = JSON.parse(body).data;
console.log(jawboneData);
return done(null, jawboneData, console.log('Jawbone UP data ready to be displayed.'));
}
});
}));
// HTTPS
var secureServer = https.createServer(sslOptions, app).listen(port, function(){
console.log('UP server listening on ' + port);
});

You weren't too far off, you were already getting the token. To make your code work a few steps are needed:
Add the concept of a "session", data that exists from request to request as a global variable. When you do a full web app use express-sessions and passport-sessions and implement user management. But for now we just add a global for a single user state.
var demoSession = {
accessToken: '',
refreshToken: ''
};
Pass in a user object in the done() of JawboneStrategy. This is because the "authorize" feature of passport is expecting a user to exist in the session. It attaches the authorize results to this user. Since we are just testing the API just pass in an empty user.
// Setup the passport jawbone authorization strategy
passport.use('jawbone', new JawboneStrategy({
clientID: jawboneAuth.clientID,
clientSecret: jawboneAuth.clientSecret,
authorizationURL: jawboneAuth.authorizationURL,
tokenURL: jawboneAuth.tokenURL,
callbackURL: jawboneAuth.callbackURL
}, function(accessToken, refreshToken, profile, done) {
// we got the access token, store it in our temp session
demoSession.accessToken = accessToken;
demoSession.refreshToken = refreshToken;
var user = {}; // <-- need empty user
done(null, user);
console.dir(demoSession);
}));
Use a special page to show the data "/data". Add a route to separate the auth from the display of service.
app.get('/done', passport.authorize('jawbone', {
scope: ['basic_read','sleep_read'],
failureRedirect: '/'
}), function(req, res) {
res.redirect('/data');
}
);
Lastly the Jawbone Up sleeps API is a little tricky. you have to add a YYYYMMDD string to the request:
app.get('/data', function(req, res) {
var options = {
access_token: demoSession.accessToken,
client_id: jawboneAuth.clientID,
client_secret: jawboneAuth.clientSecret
};
var up = require('jawbone-up')(options);
// we need to add date or sleep call fails
var yyyymmdd = (new Date()).toISOString().slice(0, 10).replace(/-/g, "");
console.log('Getting sleep for day ' + yyyymmdd);
up.sleeps.get({date:yyyymmdd}, function(err, body) {
if (err) {
console.log('Error receiving Jawbone UP data');
} else {
try {
var result = JSON.parse(body);
console.log(result);
res.render('userdata', {
requestTime: result.meta.time,
jawboneData: JSON.stringify(result.data)
});
}
catch(err) {
res.render('userdata', {
requestTime: 0,
jawboneData: 'Unknown result'
});
}
}
});
});
I have created a gist that works for me here thats based on your code: https://gist.github.com/longplay/65056061b68f730f1421

The Jawbone access token expires in 1 year so you definitely don't need to re-authenticate the user each time. Also you are provided with a refresh_token as well, so you can refresh the access token when needed.
Once you have the access_token you have to store it somewhere, preferably in some sort of a database or a file storage for later use, then you use that token for each request made to the Jawbone REST API.
The jawbone-up module uses request internally, so I'm going to show you how to make a request with it (it should be pretty much the same with any other module).
Here is how you can get the user's profile (the most basic API call):
var request = require('request')
request.get({
uri:'https://jawbone.com/nudge/api/v.1.1/users/#me',
auth:{bearer:'[ACCESS_TOKEN]'},
json:true
}, function (err, res, body) {
// body is a parsed JSON object containing the response data
})
There is another module called Purest which also uses request internally, but hides some of the complexity around using a REST API. Here is how the same request would look like using that module:
var Purest = require('purest')
var jawbone = new Purest({provider:'jawbone'})
jawbone.get('users/#me', {
auth:{bearer:'[ACCESS_TOKEN]'}
}, function (err, res, body) {
// body is a parsed JSON object containing the response data
})
Alternatively for authenticating the user (getting the access_token) you can use another module called Grant which I personally use, but either one should work.

Related

Passport.js / Google OAuth2 strategy - How to use token on login for API access

I am logging users in via their domain Google accounts using passport.js. This works great, but now I need to give this application access to a few Google API's (drive, sheets, etc).
When a user logs in, a message appears in the logs, that makes it seem like passport has all the required info:
info: [06/Jun/2019:21:24:37 +0000] "302 GET /auth/callback?code=** USER ACCESS TOKEN HERE **&scope=email%20profile%20https://www.googleapis.com/auth/drive.file%20https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/drive HTTP/1.1" [46]
This is achieved by passing the appended scopes via passport.authenticate(), which presents the user with the "Grant access to these things on your Google account to this app?" screen :
//Initial auth call to Google
router.get('/',
passport.authenticate('google', {
hd: 'edmonds.wednet.edu',
scope: [
'email',
'profile',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/spreadsheets'
],
prompt: 'select_account'
})
);
However, when I go and try to call an API with something like:
const {google} = require('googleapis');
const sheets = google.sheets({version: 'v4', auth});
router.post('/gsCreate', function(req,res,next){
sheets.spreadsheets.create({
// Details here.....
});
});
I get nothing but errors (the current one is debug: authClient.request is not a function)
My question is: Is it possible for me to use a setup like this, asking the user to log in and grant permissions once, and then somehow save that to their user session via passport?
I had the same question, but I was able to access Google Gmail API functionalities along with Passport.js user authentication by specifying 'scopes' using the following process.
First, create a file to setup the passport-google-strategy in nodejs as follows.
passport_setup.js
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20')
const fs = require("fs");
const path = require('path');
//make OAuth2 Credentials file using Google Developer console and download it(credentials.json)
//replace the 'web' using 'installed' in the file downloaded
var pathToJson = path.resolve(__dirname, './credentials.json');
const config = JSON.parse(fs.readFileSync(pathToJson));
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
const query = { _id: id }
Users.findOne(query, (err, user) => {
if (err) {
res.status(500).json(err);
} else {
done(null, user)
}
})
})
//create a google startergy including following details
passport.use(
new GoogleStrategy({
clientID: config.installed.client_id,
clientSecret: config.installed.client_secret,
callbackURL: config.installed.redirect_uris[0]
}, (accessToken, refreshToken,otherTokenDetails, user, done) => {
//in here you can access all token details to given API scope
//and i have created file from that details
let tokens = {
access_token: accessToken,
refresh_token: refreshToken,
scope: otherTokenDetails.scope,
token_type: otherTokenDetails.token_type,
expiry_date:otherTokenDetails.expires_in
}
let data = JSON.stringify(tokens);
fs.writeFileSync('./tokens.json', data);
//you will get a "user" object which will include the google id, name details,
//email etc, using that details you can do persist user data in your DB or can check
//whether the user already exists
//after persisting user data to a DB call done
//better to use your DB user objects in the done method
done(null, user)
})
)
Then create your index.js file in nodejs for API route management and to call send method of Gmail API.
Also, run the following command to install "google-apis"
npm install googleapis#39 --save
index.js
const express = require("express")
//import passport_setup.js
const passportSetup = require('./passport_setup')
const cookieSeesion = require('cookie-session');
const passport = require("passport");
//import google api
const { google } = require('googleapis');
//read credentials file you obtained from google developer console
const fs = require("fs");
const path = require('path');
var pathToJson_1 = path.resolve(__dirname, './credentials.json');
const credentials = JSON.parse(fs.readFileSync(pathToJson_1));
//get Express functionalities to app
const app = express();
// **Middleware Operations**//
//cookie encryption
app.use(cookieSeesion({
name:'Reserve It',
maxAge: 1*60*60*1000,
keys: ['ranmalc6h12o6dewage']
}))
//initialize passort session handling
app.use(passport.initialize())
app.use(passport.session())
app.use(express.json());
//**API urls**//
//route to authenticate users using google by calling google stratergy in passport_setup.js
//mention access levels of API you want in the scope
app.get("/google", passport.authenticate('google', {
scope: ['profile',
'email',
'https://mail.google.com/'
],
accessType: 'offline',
prompt: 'consent'
}))
//redirected route after obtaining 'code' from user authentication with API scopes
app.get("/google/redirect", passport.authenticate('google'), (req, res) => {
try {
//read token file you saved earlier in passport_setup.js
var pathToJson_2 = path.resolve(__dirname, './tokens.json');
//get tokens to details to object
const tokens = JSON.parse(fs.readFileSync(pathToJson_2));
//extract credential details
const { client_secret, client_id, redirect_uris } = credentials.installed
//make OAuth2 object
const oAuth2Client = new google.auth.OAuth2(client_id,
client_secret,
redirect_uris[0])
// set token details to OAuth2 object
oAuth2Client.setCredentials(tokens)
//create gmail object to call APIs
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
//call gmail APIs message send method
gmail.users.messages.send({
userId: 'me',//'me' indicate current logged in user id
resource: {
raw: //<email content>
}
}, (err, res) => {
if (err) {
console.log('The API returned an error: ' + err)
throw err
}
console.log('Email Status : ' + res.status)
console.log('Email Status Text : ' + res.statusText)
})
res.status(200).json({ status:true })
} catch (err) {
res.status(500).json(err)
}
})
app.listen(3000, () => { console.log('Server Satrted at port 3000') })
You can separate the routes in the index.js file to different files for clarity using express.Router()
If you want to call another Google API service just change this code segment and code below that;
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
gmail.users.messages.send(....Send Method internal implementation given above....)
For Google Drive:
const drive = google.drive({version: 'v3', auth: oAuth2Client});
drive.files.list(...Refer "Google Drive API" documentation for more details....)
I believe you can't use passport.js for three-legged oauth for APIs like Sheets or Drive.
Have a look at the Using OAuth for web servers documentation instead.
user835611 has the correct answer, as that page explains everything quite nicely. However, if you still need more, the below link really helped me to understand how this works.
https://github.com/googleapis/google-auth-library-nodejs#oauth2

How do I store and send authorization tokens with API requests using OAuth?

I'm trying to set my application up so I can use the Spotify API. Their API requires an Authorization token along with every request, and this token is different every user session. I have successfully implemented OAuth2 login using the 'passport-spotify' module (detail below) and have the token, which I am currently storing in my database. Once it is in the database, it is also available in my Redux store.
Functioning Passport strategy:
const spotifyConfig = {
clientID: process.env.SPOTIFY_CLIENT_ID,
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
callbackURL: process.env.SPOTIFY_CALLBACK
}
const strategy = new SpotifyStrategy(spotifyConfig, (accessToken, refreshToken, profile, done) => {
const spotifyId = profile.id
const name = profile.displayName
const email = profile.emails[0].value
User.find({where: {spotifyId}})
.then(foundUser => (foundUser
? foundUser.update({accessToken, refreshToken}).then(() => done(null, foundUser))
: User.create({name, email, spotifyId, accessToken, refreshToken})
.then(createdUser => done(null, createdUser))
))
.catch(done)
})
passport.use(strategy)
router.get('/', passport.authenticate('spotify', {scope: ['user-read-email'], showDialog: true}))
router.get('/callback', passport.authenticate('spotify', {
successRedirect: '/home',
failureRedirect: '/login'
}))
What I am currently stuck on is how to set up my API requests so it accesses that token on every call. The 'spotify-web-api-node' node module has a setCredentials method, but I can't figure out how to access the token.
Semi-functioning API call (it makes the API request but gives me a 403 unauthorized):
const SpotifyWebApi = require('spotify-web-api-node');
const spotifyApi = new SpotifyWebApi();
spotifyApi.setCredentials({
clientId: 'my client id',
clientSecret: 'my client secret',
redirectUri: 'http://localhost:8888/auth/spotify/callback',
refreshToken: 'cant figure out how to properly include this',
accessToken: 'and this.',
});
export function searchMetallica(){
return spotifyApi.searchArtists('Metallica')
.then(function(data) {
console.log(data.body);
}, function(err) {
console.error(err);
});
}
I hope this isn't too much a of a newbie question. Thanks in advance.
You're very close!
You need to pass the token to the setAccessToken() method on the Spotify wrapper, in your case:
spotifyApi.setAccessToken(<youraccesstoken>);
You can set the refresh token in a predictably similar way:
spotifyApi.setRefreshToken(<yourrefreshtoken>);
Easy peasy!
But, there's a catch. If you use this spotifyApi for all your calls, this will set the same access token for all those calls! You need to make sure to use the appropriate access token for each user, so user A can't do actions for user B and vice versa.
You can get around this by simply instantiating the API wrapper and setting the access token at the point when the user logs in, or at the point when the call is made. For example, a call to get top tracks may look like (using Express for convenience):
app.get('/myendpoint', function (request, response) {
const loggedInSpotifyApi = new SpotifyWebApi();
loggedInSpotifyApi.setAccessToken(request.access_token);
// Get top tracks!
loggedInSpotifyApi.getMyTopTracks()
.then(function(data) {
response.send(data.body);
}, function(err) {
console.error(err);
});
});
Here's a full working Glitch that shows the Authorization Code flow and spotify-web-api-node: https://glitch.com/edit/#!/spotify-authorization-code
Let me know if you have any questions!

NodeJS, Express, Mongoose RESTFul Api access only by the server itself

I've built a simple RESTful API using NodeJS, Mongoose, and Express. I am using the database to store simple string quotes and am not planning to allow access to any other users to the database nor to the api.
I've read up on securing my RESTful API but it seems as if most methods focus on using a username and password to limit access. However, that seems like an overkill for such a simple API especially since i do not consider on allowing anyone else access except for requests that come from the server itself.
So I want to make it so that if anyone else tries to access the API he would be denied access. The only way the API should be accessible is from requests from the server itself i.e from the JavaScript files on the server.
I am currently learning all those things so sorry if i am not using the proper technical terminology :)
I am considering doing something like checking the IP of the person/thing trying to access the API and if that is not the ip of the server then deny access. Would something like this work and how would I got about implementing it.
EDIT: I am looking for something simple since I dont think that most people will take the time to 'hack' the API just so they can access a database of quotes.
Here is my server.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var Quote = require('./mongodb/models/mainModel.js');
mongoose.connect('mongodb://localhost:27017/myappdb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080;
var router = express.Router();
function grantAccess(req) {
if(req.ip === '::1' ||
req.ip === '127.0.0.1' ||
req.ip === '::ffff:127.0.0.1') {
return true;
}
return ["IP Address Unknown " + req.ip]
}
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
router.route('/maindb')
.post(function(req, res) {
var quote = new Quote();
quote.name = req.body.name;
quote.severity = req.body.severity;
quote.createdAt = new Date();
quote.updatedAt = new Date();
quote.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Quote created!' });
});
})
.get(function(req, res) {
if(grantAccess(req) !== 'boolean')
Quote.find(function(err, quotes) {
if (err)
res.send(err);
res.json(quotes);
});
});
router.route('/maindb/:quote_id')
.get(function(req, res) {
Quote.findById(req.params.quote_id, function(err, quote) {
if (err)
res.send(err);
res.json(quote);
});
})
.put(function(req, res) {
Quote.findById(req.params.quote_id, function(err, quote) {
if (err)
res.send(err);
quote.name = req.body.name;
quote.severity = req.body.severity;
quote.updatedAt = new Date();
// save the bear
quote.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Quote updated!' });
});
});
})
.delete(function(req, res) {
Quote.remove({
_id: req.params.quote_id
}, function(err, quote) {
if (err)
res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
app.use('/api', router);
app.listen(port);
console.log('Magic happens on port ' + port);
you can add apiKey in your project. It will be required if anyone hits any of your api.
exmaple:
"apiKeys": {
"web": "7fe642cabe6855cd4175937fa8fadd876c1af6b499ab941db6a8a362c0f30f97"
}
similarly you can set apikey for mobile user or accordance to requirment of project.
Link to genrate RandomKey
By this you will allow only those users who have your api key.As api key is shared by you so you will provide it to only appropriate user.
Api key checking:
You can check api key as first middleware before any request to server
example:
router.use(function(req,res,next){
var apiKey = req.get('api_key'); // assuming user will send api key in headers
// code to check api key basic comparison
})

Passport JWT req.user is undefined in one of my routes

I'm having an absolute nightmare trying to set up JWT with my express app! Think I've got it mostly working now, I have a register route and login route that both work correctly and generate valid tokens and I have another route in my '/users' route that I test the authentication with and this is all fine. But I have another file containing routes for '/api' which is where the authentication is actually important and I have a similar test route that tries to access req.user (just like I do in my other route) but it seems like req.user is undefined. Through some debugging it looks like the user is in req.account which is very odd and I don't understand why its not in req.user
I define my jwt strategy in /config/passport.js
'use strict';
const User = require('../models/user'),
config = require('./main'),
JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
//exported to be used by passport in server set up
module.exports = function (passport) {
const jwtOptions = {
// Telling Passport to check authorization headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling Passport where to find the secret
secretOrKey: config.secret
};
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
User.findById(payload._id, function(err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
passport.use(jwtLogin);
}
passport is passed as an argument to this and then initialised in the main express file
here is the /users route file, this works fine. sending a GET request to /users/isAuth with Authorization header and 'JWT ' works fine and I get my username sent back to me
"use strict";
const express = require('express'),
router = express.Router(),
jwt = require('jsonwebtoken'),
User = require('../models/user'),
config = require('../config/main'),
passport = require ('passport');
function generateToken(user) {
return jwt.sign({_id: user._id}, config.secret, {
expiresIn: 10080
});
}
.
. Here are routes for login and register they perform as expected
. and work fine
.
/* ==================================
Test Authentication Route
================================== */
router.get('/isAuth', passport.authenticate('jwt', { session: false }), function(req, res) {
console.log(req.user);
res.json({username: req.user.username});
});
module.exports = router;
In this file though, for the api routes sending a request to GET /api/testAuth exactly the same as before with the same token and the same headers I get back no req.user and in the console I see that req.user is undefined. But in the console there does seem to be the user object just as req.account? I don't understand what is happening here hopefully someone can help!
"use strict";
const express = require('express'),
router = express.Router(),
jwt = require('jsonwebtoken'),
Server = require('../models/server'),
passport = require('passport');
// Test route to see if logged in user is matt
router.get('/testAuth', passport.authorize('jwt', { session: false }), function(req, res) {
console.log(req.user);
if (req.user) {
if(req.user.username == "matt") {
res.send("You are matt!");
} else {
res.send("You are not matt!");
}
} else {
res.send("no req.user");
}
})
module.exports = router;
req.user object is only set when you use a passport authentication strategy that uses sessions. In this case, the authentication is stateless since you have specified {session: false}, which is how it should be for an api. Thus, the session does not have a user object. Here is how I set my req.user object in the passport.authenticate middleware:
Modify your jwtOptions to enable passing the req object to JwtStrategy function:
const jwtOptions = {
// Telling Passport to check authorization headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling Passport where to find the secret
secretOrKey: config.secret,
passReqToCallback: true, //<= Important, so that the verify function can accept the req param ie verify(req,payload,done)
};
Modify the parameters to your JwtStrategy to include the request object as the first parameter; then within the if (user) block, just assign the returned user object to req.user:
const jwtLogin = new JwtStrategy(jwtOptions, function(req, payload, done) {
User.findById(payload._id, function(err, user) {
if (err) { return done(err, false); }
if (user) {
req.user = user; // <= Add this line
done(null, user);
} else {
done(null, false);
}
});
});
That is it: now any route that has the passport.authenticate("jwt", {session: false}) middleware will receive req.user upon successful authentication.
You are using passport.authorize in your testAuth route, this is for users that are already logged in and have session information. Since you are not using session storage you do not have a persistent req.user object and so should use passport.authenticate on all routes
http://passportjs.org/docs/authorize

Loopback IO OAuth not working

I am trying to get a https loopback server up and running protected by OAuth. I am using the loopback gateway sample project as a reference. But for some reason I can't get the OAuth piece to work. What I mean is, even after adding in the OAuth bits and pieces, the APIs don't seem to be protected. I get a response back even if there is no token in my request. This is what my server.js looks like
var loopback = require('loopback');
var boot = require('loopback-boot');
var https = require('https');
var path = require('path');
var httpsRedirect = require('./middleware/https-redirect');
var site = require('./site');
var sslConfig = require('./ssl-config');
var options = {
key: sslConfig.privateKey,
cert: sslConfig.certificate
};
var app = module.exports = loopback();
// Set up the /favicon.ico
app.middleware('initial', loopback.favicon());
// request pre-processing middleware
app.middleware('initial', loopback.compress());
app.middleware('session', loopback.session({ saveUninitialized: true,
resave: true, secret: 'keyboard cat' }));
// -- Add your pre-processing middleware here --
// boot scripts mount components like REST API
boot(app, __dirname);
// Redirect http requests to https
var httpsPort = app.get('https-port');
app.middleware('routes', httpsRedirect({httpsPort: httpsPort}));
var oauth2 = require('loopback-component-oauth2')(
app, {
// Data source for oAuth2 metadata persistence
dataSource: app.dataSources.pg,
loginPage: '/login', // The login page url
loginPath: '/login' // The login processing url
});
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Set up login/logout forms
app.get('/login', site.loginForm);
app.get('/logout', site.logout);
app.get('/account', site.account);
app.get('/callback', site.callbackPage);
var auth = oauth2.authenticate({session: false, scope: 'demo'});
app.use(['/protected', '/api', '/me', '/_internal'], auth);
app.get('/me', function(req, res) {
// req.authInfo is set using the `info` argument supplied by
// `BearerStrategy`. It is typically used to indicate scope of the token,
// and used in access control checks. For illustrative purposes, this
// example simply returns the scope in the response.
res.json({ 'user_id': req.user.id, name: req.user.username,
accessToken: req.authInfo.accessToken });
});
signupTestUserAndApp();
//var rateLimiting = require('./middleware/rate-limiting');
//app.middleware('routes:after', rateLimiting({limit: 100, interval: 60000}));
//var proxy = require('./middleware/proxy');
//var proxyOptions = require('./middleware/proxy/config.json');
//app.middleware('routes:after', proxy(proxyOptions));
app.middleware('files',
loopback.static(path.join(__dirname, '../client/public')));
app.middleware('files', '/admin',
loopback.static(path.join(__dirname, '../client/admin')));
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.middleware('final', loopback.urlNotFound());
// The ultimate error handler.
app.middleware('final', loopback.errorHandler());
app.start = function(httpOnly) {
if(httpOnly === undefined) {
httpOnly = process.env.HTTP;
}
server = https.createServer(options, app);
server.listen(app.get('port'), function() {
var baseUrl = (httpOnly? 'http://' : 'https://') + app.get('host') + ':' + app.get('port');
app.emit('started', baseUrl);
console.log('LoopBack server listening # %s%s', baseUrl, '/');
});
return server;};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
function signupTestUserAndApp() {
// Create a dummy user and client app
app.models.User.create({username: 'bob',
password: 'secret',
email: 'foo#bar.com'}, function(err, user) {
if (!err) {
console.log('User registered: username=%s password=%s',
user.username, 'secret');
}
// Hack to set the app id to a fixed value so that we don't have to change
// the client settings
app.models.Application.beforeSave = function(next) {
this.id = 123;
this.restApiKey = 'secret';
next();
};
app.models.Application.register(
user.username,
'demo-app',
{
publicKey: sslConfig.certificate
},
function(err, demo) {
if (err) {
console.error(err);
} else {
console.log('Client application registered: id=%s key=%s',
demo.id, demo.restApiKey);
}
}
);
});
}
I don't get any errors when the server starts up. Thoughts?
Got it figured. More information here https://github.com/strongloop/loopback-gateway/issues/17, but basically I had my rest-api middleware not configured right.

Categories

Resources