Spotify authorization code grant: Bad Request - javascript

I am trying to create a website that uses the Spotify APIs and I am stuck trying to get the authorization code flow to work. Below is the code that I am using.
app.get('/login', function(req, res) {
var scope = 'user-read-private';
res.redirect('https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: clientId,
scope: scope,
redirect_uri: redirectUri,
state: state
}));
});
app.get('/callback', function(req, res) {
res.status(200);
var code = req.query.code;
console.log('\ncode:', code, '\n');
spotify.authorizationCodeGrant(code).then(
function(data) {
console.log('The access token expires in ' + data.body['expires_in']);
console.log('The access token is ' + data.body['access_token']);
spotify.setAccessToken(data.body['access_token']);
spotify.setRefreshToken(data.body['refresh_token']);
},
function(err) {
console.log('Could not login!', err);
}
);
res.redirect('/');
});
The problem that I am having is that when it gets to the authorizeCodeGrant call it just fails and gives me a 400 bad request error and I am not sure why because I know that I am getting a code from Spotify, the code just does not seem to work.
var path = require('path');
var express = require('express');
var request = require('request');
var exphbs = require('express-handlebars');
var querystring = require('querystring');
var url = require('url');
var Spotify = require('spotify-web-api-node');
var keys = require('./keys');
var scopes = ['playlist-modify-private', 'user-read-private'],
redirectUri = 'http://localhost:3000/callback',
clientId = 'client_id',
clientSecret = 'client_secret',
state = 'some-state-of-my-choice';
var spotify = new Spotify({
redirectUri: redirectUri,
clientId: clientId,
redirectUri: redirectUri
});
var results = [];
var login = 1;//keeps track if logged into spotify
var tokenExpiration;
var app = express();
var port = process.env.PORT || 3000;
app.engine('handlebars', exphbs({ defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.get('/', function(req, res, next){
res.status(200);
res.render('searchPage', {
login: login,
results: results
});
});
app.get('/login', function(req, res) {
var scope = 'user-read-private';
res.redirect('https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: clientId,
scope: scope,
redirect_uri: redirectUri,
state: state
}));
});
app.get('/callback', function(req, res) {
var code = req.query.code;
console.log('\ncode:', code, '\n');
spotify.authorizationCodeGrant(code).then(
function(data) {
console.log('The access token expires in ' + data.body['expires_in']);
console.log('The access token is ' + data.body['access_token']);
spotify.setAccessToken(data.body['access_token']);
spotify.setRefreshToken(data.body['refresh_token']);
tokenExpiration = new Data().getTime()/1000 + data.body['expires_in'];
login = 0;
},
function(err) {
console.log('Could not login!', err);
}
);
if(login == 0){
res.redirect('/#' +
querystring.stringify({
access_token: spotify.getAccessToken(),
refresh_token: spotify.getRefreshToken()
}));
}else{
res.redirect('/');
}
});
var numberOfTimesUpdated = 0;
setInterval(function() {
if(++numberOfTimesUpdated > 5 && login == 0) {
clearInterval(this);
spotify.refreshAccessToken().then(
function(data) {
tokenExpiration = new Data().getTime()/1000 + data.body['expires_in'];
spotify.setAccessToken(data.body['access_token']);
},
function(err) {
console.log('Could not refresh the token!', err.message);
}
);
}
}, 1000);
app.post('/search/:title', function(req, res) {
var search = req.params.title.toLowerCase();//req.body.search;
console.log('search', search);
resutls = [];
spotify.searchTracks(search, function(err, data) {
if(err) {
console.error('something went wrong...');
return;
}
console.log('I got' + search.body.tracks.total + 'results!');
search.body.tracks.items.forEach(function(track){
results.push({
artist: track.artist[0].name,
song: track.name,
preview: track.external_urls.sp,
album: track.album.name
});
res.render('searchPage', {
login: login,
results: results
});
});
});
});
app.use(express.static('public'));
app.listen(port, function(err){
console.log("== Server is listening on port", port);
});
Above is the full code for the server.

Related

Authentication with NodeJS, Express-Session and Passport fails

I am successfully authenticating and logging in with the google OAuth API.
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const passportInit = require('./app/routes/auth')
const session = require('express-session');
module.exports = (app, db, passport) => {
app.use(session({secret: "ahskfjdhkjshadkjfhlajsdhlfkj"}));
passportInit(passport)
app.use(passport.initialize());
app.use(passport.session())
app.get('/', (req, res) => {
if (req.session.token) {
res.cookie('token', req.session.token);
res.json({
status: 'session cookie set'
});
console.log(req.session.token);
console.log(JSON.stringify(req.user))
} else {
res.cookie('token', '')
res.json({
status: 'session cookie not set'
});
}
});
app.get('/auth/google', passport.authenticate('google', {
scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/youtube']
}));
app.get('/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/' // Fail: To err Page
}),
(req, res) => {
req.session.token = req.user.token;
userString = JSON.stringify(req.user);
userObjectValue = JSON.parse(userString);
userId = userObjectValue['profile'].id;
userName = userObjectValue['profile'].name;
userGivenName = userName.givenName;
const details = {'userId': userId};
db.collection('users').findOne(details, (err, item) => {
if (item == null) {
res.redirect('http://localhost:80/Register.html');
} else {
if(item['rolle'] == 'yt') {
res.redirect('http://localhost:80/YT_Welcome.html');
} else {
res.redirect('http://localhost:80/WT_Welcome.html');
}
}
});
}
);
app.get('/logout', (req, res) => {
req.logout();
req.session.token = null;
res.redirect('/');
});
}
Now I want to make a POST request from my frontend to my NodeJS backend.
Frontend-Request:
function registerWT() {
console.log('registerWT started...')
var rolle = 'wt';
var json = {"rolle": rolle};
$.ajax({
url: 'http://localhost:8000/user',
type: 'POST',
data: JSON.stringify(json),
contentType: 'application/json; charset=utf-8',
dataType: 'JSON',
async: false,
success: function (msg) {
var js = JSON.stringify(msg);
var state = msg['state'];
if (state == true) {
console.log('successfully created new user')
} else {
console.log('failed to create new user')
}
}
});
Backend-API:
var ObjectID = require('mongodb').ObjectID;
const passport = require('passport');
const passportInit = require('./auth');
module.exports = (app, db) => {
app.post('/user', (req, res) => {
console.log("POST USER REACHED!"); // This is printed out...
console.log(req.body.rolle); //is printed out correctly
console.log(req.user); // Is undefined...
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) } //Authentication fails...
console.log(req.user.userId);
console.log(req.userGivenName);
console.log(req.body.rolle);
userId = req.user.userId;
userGivenName = req.user.userGivenName;
userRolle= req.body.rolle;
const details = { userId: userId, userGivenName: userGivenName, rolle: userRolle };
db.collection('users').insert(details, (err, result) => {
if (err) {
res.send({ 'error': 'An error has occurred' });
} else {
res.send(result.ops[0]);
}
});
});
}
From my understanding the user authentication data should be send automaticly with every request I am doing from my frontend to my backend, since I logged in via google before. Is this correct or do I miss to include something in my frontend JS request code?
What is interessting is that after I logged in, I have to trouble with navigating to /user. So there is no problem with manualy doing a get request to this API, where I am also checking for authentication.
app.get('/user', (req, res) => {
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) }
db.collection('users').find({}).toArray((err, item) => {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.json(item)
}
});
});
But when I am making a Get request with JavaScript, the authentication fails again...
JavaScript get request:
function getTest() {
console.log('YT');
$.ajax({
url: 'http://localhost:8000/user',
type: 'GET',
async: false,
success: function (msg) {
var state = msg['state']; //nehmen den Wert von state aus der JSON
if (state == true) {
console.log('successfully created new user')
} else {
console.log('failed to create new user')
}
}
});
}
Does someone know what I am doing wrong here?
Edit:
My passportInit:
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const keys = require('../../config/keys')
module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
passport.use(new GoogleStrategy({
clientID: keys.google.clientID,
clientSecret: keys.google.cientSecret,
callbackURL: keys.google.callback
},
(token, refreshToken, profile, done) => {
return done(null, {
profile: profile,
token: token
});
}));
};
Edit2: Added cors package:
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const db = require('./config/db');
const keys = require('./config/keys')
const passport = require('passport');
const express = require('express');
const app = express();
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const cors = require('cors')
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors({ origin: 'http://localhost' })); //configuring cors
MongoClient.connect(db.url, (err, database) => {
if (err) return console.log(err)
app.options('*', cors()) // enable pre-flight across-the-board
require('./authenticate')(app, database,passport);
require('./app/routes')(app, database, passport);
app.listen(port, () => {
console.log('We are live on ' + port);
});
});
I finally was able to solve the problem.
No, Browser Plug-in or something like this is needed!
Please see my Code below.
Frontend-Request:
function register() {
var role = 'wt';
var json = {"role": role};
$.ajax({
url: 'http://localhost:8000/user',
type: 'POST',
data: JSON.stringify(json),
contentType: 'application/json; charset=utf-8',
dataType: 'JSON',
xhrFields: {
withCredentials: true
},
crossDomain: true,
async: false,
success: function (msg) {
var state = msg['state'];
if (state == true) {
console.log('successfully created new WT')
location.href = 'http://localhost:80/WT_Welcome.html'
} else {
console.log('failed to create new WT')
location.href = 'http://localhost:80/index.html'
}
}
});
}
Backend Server.js
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const db = require('./config/db');
const keys = require('./config/keys')
const passport = require('passport');
const express = require('express');
const app = express();
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
MongoClient.connect(db.url, (err, database) => {
if (err) return console.log(err)
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', "http://localhost");
res.header('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Credentials', true)
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
})
require('./authenticate')(app, database,passport);
require('./app/routes')(app, database, passport);
app.listen(port, () => {
console.log('We are live on ' + port);
});
});
Backend API:
app.post('/user', (req, res) => {
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) } //Authentication fails...
userString = JSON.stringify(req.user);
userObject = JSON.parse(userString)
userId = userObjectValue['profile'].id;
userName = userObjectValue['profile'].name; //not used
userGivenName = userName.givenName;
userRolle= req.body.rolle;
const details = { userId: userId, userGivenName: userGivenName, rolle: userRolle };
console.log(details);
db.collection('users').insert(details, (err, result) => {
if (err) {
res.send({ 'state': false });
} else {
res.send({'state' : true});
}
});
});

Gmail API sending email error 401:Invalid Credentials

I'm developing with express a web page that when the client clicks in "Send E-mail" redirect to google asking for permission to send email through the client email and after the client gave the permission redirect back and send the email.
The code so far:
'use strict';
const express = require('express');
const googleAuth = require('google-auth-library');
const request = require('request');
let router = express.Router();
let app = express();
const SCOPES = [
'https://mail.google.com/'
,'https://www.googleapis.com/auth/gmail.modify'
,'https://www.googleapis.com/auth/gmail.compose'
,'https://www.googleapis.com/auth/gmail.send'
];
const clientSecret = '***********';
const clientId = '**************';
const redirectUrl = 'http://localhost:8080/access-granted';
const auth = new googleAuth();
const oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
function sendEmail(auth, content, to , from, subject) {
let encodedMail = new Buffer(
`Content-Type: text/plain; charset="UTF-8"\n` +
`MIME-Version: 1.0\n` +
`Content-Transfer-Encoding: 7bit\n` +
`to: ${to}\n` +
`from: ${from}\n` +
`subject: ${subject}\n\n` +
content
)
.toString(`base64`)
.replace(/\+/g, '-')
.replace(/\//g, '_');
request({
method: "POST",
uri: `https://www.googleapis.com/gmail/v1/users/me/messages/send`,
headers: {
"Authorization": `Bearer ${auth}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"raw": encodedMail
})
},
function(err, response, body) {
if(err){
console.log(err); // Failure
} else {
console.log(body); // Success!
}
});
}
app.use('/static', express.static('./www'));
app.use(router)
router.get('/access-granted', (req, res) => {
sendEmail(req.query.code, 'teste email', 'teste#gmail.com', 'teste#gmail.com', 'teste');
res.sendfile('/www/html/index.html', {root: __dirname})
})
router.get('/request-access', (req, res) => {
res.redirect(authUrl);
});
router.get('/', (req, res) => {
res.sendFile('/www/html/index.html', { root: __dirname });
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
module.exports = app;
Every time I try to send a simple E-mail I receive the error 401: Invalid Credentials. But I'm passing in Authorization the client code auth that google sends just gave me...
The recommended way to use google APIs is to use Google API nodejs client which also provides Google OAuth flow. You can then use google.gmail('v1').users.messages.send to send the email :
const gmail = google.gmail('v1');
gmail.users.messages.send({
auth: oauth2Client,
userId: 'me',
resource: {
raw: encodedMail
}
}, function(err, req) {
if (err) {
console.log(err);
} else {
console.log(req);
}
});
auth is OAuth2, the OAuth object that can be populated with your token. You can get the token in the express session :
var oauth2Client = getOAuthClient();
oauth2Client.setCredentials(req.session["tokens"]);
which you've already stored in your OAuth callback endpoint :
var oauth2Client = getOAuthClient();
var session = req.session;
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
// Now tokens contains an access_token and an optional refresh_token. Save them.
if (!err) {
oauth2Client.setCredentials(tokens);
session["tokens"] = tokens;
res.send(`<html><body><h1>Login successfull</h1><a href=/send-mail>send mail</a></body></html>`);
} else {
res.send(`<html><body><h1>Login failed</h1></body></html>`);
}
});
Here is a complete example inspired from this google API oauth for node.js example :
'use strict';
const express = require('express');
const google = require('googleapis');
const request = require('request');
const OAuth2 = google.auth.OAuth2;
const session = require('express-session');
const http = require('http');
let app = express();
app.use(session({
secret: 'some-secret',
resave: true,
saveUninitialized: true
}));
const gmail = google.gmail('v1');
const SCOPES = [
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.send'
];
const clientSecret = 'CLIENT_SECRET';
const clientId = 'CLIENT_ID';
const redirectUrl = 'http://localhost:8080/access-granted';
const mailContent = "test";
const mailFrom = "someemail#gmail.com";
const mailTo = "someemail#gmail.com";
const mailSubject = "subject";
function getOAuthClient() {
return new OAuth2(clientId, clientSecret, redirectUrl);
}
function getAuthUrl() {
let oauth2Client = getOAuthClient();
let url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
//use this below to force approval (will generate refresh_token)
//approval_prompt : 'force'
});
return url;
}
function sendEmail(auth, content, to, from, subject, cb) {
let encodedMail = new Buffer(
`Content-Type: text/plain; charset="UTF-8"\n` +
`MIME-Version: 1.0\n` +
`Content-Transfer-Encoding: 7bit\n` +
`to: ${to}\n` +
`from: ${from}\n` +
`subject: ${subject}\n\n` +
content
)
.toString(`base64`)
.replace(/\+/g, '-')
.replace(/\//g, '_');
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: encodedMail
}
}, cb);
}
app.use('/send-mail', (req, res) => {
let oauth2Client = getOAuthClient();
oauth2Client.setCredentials(req.session["tokens"]);
sendEmail(oauth2Client, mailContent, mailTo, mailFrom, mailSubject, function(err, response) {
if (err) {
console.log(err);
res.send(`<html><body><h1>Error</h1><a href=/send-mail>send mail</a></body></html>`);
} else {
res.send(`<html><body><h1>Send mail successfull</h1><a href=/send-mail>send mail</a></body></html>`);
}
});
});
app.use('/access-granted', (req, res) => {
let oauth2Client = getOAuthClient();
let session = req.session;
let code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
// Now tokens contains an access_token and an optional refresh_token. Save them.
if (!err) {
oauth2Client.setCredentials(tokens);
session["tokens"] = tokens;
res.send(`<html><body><h1>Login successfull</h1><a href=/send-mail>send mail</a></body></html>`);
} else {
res.send(`<html><body><h1>Login failed</h1></body></html>`);
}
});
})
app.use('/', (req, res) => {
let url = getAuthUrl();
res.send(`<html><body><h1>Authentication using google oAuth</h1><a href=${url}>Login</a></body></html>`)
});
let port = process.env.PORT || 8080;
let server = http.createServer(app);
server.listen(port);
server.on('listening', function() {
console.log(`listening to ${port}`);
});

Passing through URL parameters through Passport OAuth flow

I currently have Google OAuth2 implemented in node.js using the excellent Passport framework, but I am finding it difficult to pass through URL parameters in the workflow.
What I'd like to do for example, would be to have a url like /analysis?id=1234 and then to be able to load that specific analysis.
It works once you are already authenticated and the session hasn't expired yet, but it doesn't work yet when you are not already authenticated. I am struggling with passing it through to the callbackURL I think. Any guidance would be appreciated!
Here is what I have thus far (relevant code only)
var session = require('express-session');
var storage = require('node-persist');
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth2').Strategy;
var GOOGLE_CLIENT_ID = "<google_client_id>"
, GOOGLE_CLIENT_SECRET = "<google_client_secret>",
GOOGLE_CALLBACKURL = "http://localhost:1425/auth/google/callback";
app.use(session({
maxAge: 86400000, // 24 hours
secret: 'no-one-will-find-out',
resave: true,
saveUninitialized: true
}));
var sess;
app.use(passport.initialize());
app.use(passport.session());
storage.initSync();
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACKURL
},
function(accessToken, refreshToken, profile, cb) {
return cb(null, profile);
}
));
passport.serializeUser( function(user, cb) {
cb(null, user);
});
passport.deserializeUser( function(obj, cb) {
cb(null, obj);
});
app.get('/login', function (req, res) {
var id = req.query_id;
if (id) {
var url = '/auth/google?id=' + id;
} else {
var url = '/auth/google';
}
res.render('landing', {url: url, layout: 'landing.hbs'});
});
app.get('/login_error', function (req, res) {
var url = '/auth/google';
res.render('landing', {url: url, error: 'show', layout: 'landing.hbs'});
});
app.get('/analysis', ensureAuthenticated, function (req, res) {
sess = req.session;
var email = res.req.user.email;
var domain = res.req.user._json.domain;
var img = res.req.user._json.image.url;
var id = req.query.id;
console.log(id);
sess.email = encodeURIComponent(email);
sess.domain = encodeURIComponent(domain);
if (domain == 'dropbox.com') {
if (id) {
res.render('index', { email: email, img: img, query: id });
} else {
res.render('index', { email: email, img: img, query: '' });
}
} else {
res.redirect('/login_error');
}
});
app.get('/auth/google', passport.authenticate('google', { scope: [
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.profile.emails.read']
}));
app.get('/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/login_error'
}),
function(req, res) {
var id = req.query.id;
// Successful authentication, redirect home.
if (id) {
res.redirect('/analysis?id=' + id);
} else {
res.redirect('/analysis');
}
}
);
function ensureAuthenticated(req, res, next) {
var id = req.query.id;
sess = req.session;
if (req.isAuthenticated()) {
return next();
} else {
console.log('need to login');
if (id) {
res.redirect('/login?id=' + id);
} else {
res.redirect('/login');
}
}
}
I'm not sure, but I believe google auth won't send you back your 'query string'.
So maybe, you could put your 'id' param in the session:
Set the session here:
app.get('/auth/google', function(req, res, next) {
req.session.analysis_id = req.query.id;
next();
}, passport.authenticate('google', { scope: [
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.profile.emails.read']
}));
Retrieve it here:
app.get('/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/login_error'
}),
function(req, res) {
var id = req.session.analysis_id;
// Successful authentication, redirect home.
if (id) {
res.redirect('/analysis?id=' + id);
} else {
res.redirect('/analysis');
}
}
);
What do you think about it?
Cheers!

Node.js SSL error - no ciphers available

I was able to upload files to dropbox using request.js module. I was trying to upload file using pure Node.js https.request() and request.write(). As dropbox needs https connection, I am using https.request(). But I am receiving error while using them(second code):
When secureProtocol is SSLv2_method:
Problem with request: 3074844416:error:140650B5:SSL routines:CLIENT_HELLO:no ciphers available:../deps/openssl/openssl/ssl/s2_clnt.c:562:
After I change secureProtocol to SSLv3_method I receive error:
Problem with request: write EPROTO 3074537216:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:../deps/openssl/openssl/ssl/s3_pkt.c:348:
I was not able to install kerberos. Could this be the problem ?
Here are my code:
Using request.js module:
At last few lines I am piping the readable stream to request.put().
var crypto = require('crypto'),
express = require('express'),
request = require('request'),
url = require('url'),
cookieParser = require('cookie-parser'),
fs = require('fs');
app = express();
app.use(cookieParser());
var APP_KEY = 'opmdwo6kpnyswfp';
var APP_SECRET = 'an6vl11lc9rp51e';
function generateCSRFToken() {
return crypto.randomBytes(18).toString('base64')
.replace(/\//g,'-').replace(/\+/g,'_');
}
function generateRedirectURI(req) {
return url.format({
protocol: req.protocol,
host: req.headers.host,
pathname: app.path() + '/callback'
});
}
function getFileSize(fileName) {
var stats = fs.statSync(fileName);
var fileSizeInBytes = stats["size"];
var fileSizeInMegaBytes = fileSizeInBytes / 1000000.0;
return fileSizeInBytes;
}
app.get('/', function(req, res, next) {
var csrfToken = generateCSRFToken();
res.cookie('csrf',csrfToken);
res.redirect(url.format({
protocol: 'https',
hostname: 'www.dropbox.com',
pathname: '1/oauth2/authorize',
query: {
client_id: APP_KEY,
response_type: 'code',
state: csrfToken,
redirect_uri: generateRedirectURI(req)
}
}));
});
app.get('/callback', function(req, res) {
if(req.query.error) {
return res.send('ERROR ' + req.query.error + ': ' +
req.query.error_description);
}
if(req.query.state !== req.cookies.csrf) {
return res.status(401).send('CSRF token mismatch, possible' +
'cross-site request forgery attempt.'
);
}
request.post('https://api.dropbox.com/1/oauth2/token', {
form: {
code: req.query.code,
grant_type: 'authorization_code',
redirect_uri: generateRedirectURI(req)
},
auth: {
user: APP_KEY,
pass: APP_SECRET
}
}, function(error, response, body) {
var data = JSON.parse(body);
if(data.error)
return res.send('ERROR: ' + data.error);
var token = data.access_token;
var fileName = "aai_success.pdf";
var path = encodeURI("https://content.dropboxapi.com/1/files_put/auto/" + fileName);
fs.createReadStream(fileName).pipe(request.put(path, {
headers: { Authorization: 'Bearer ' + token },
'Content-Length': getFileSize(fileName)
}, function(error, response, body) {
console.log(response);
}));
});
});
app.listen(3000, function() {
console.log('Application is running on port 3000');
});
Using Node.js https.request()
var crypto = require('crypto'),
https = require('https');
express = require('express'),
request = require('request'),
url = require('url'),
cookieParser = require('cookie-parser'),
fs = require('fs'),
app = express();
app.use(cookieParser());
var APP_KEY = 'opmdwo6kpnyswfp';
var APP_SECRET = 'an6vl11lc9rp51e';
function generateCSRFToken() {
return crypto.randomBytes(18).toString('base64')
.replace(/\//g,'-').replace(/\+/g,'_');
}
function generateRedirectURI(req) {
return url.format({
protocol: req.protocol,
host: req.headers.host,
pathname: app.path() + '/callback'
});
}
function getFileSize(fileName) {
var stats = fs.statSync(fileName);
var fileSizeInBytes = stats["size"];
var fileSizeInMegaBytes = fileSizeInBytes / 1000000.0;
return fileSizeInBytes;
}
app.get('/', function(req, res, next) {
var csrfToken = generateCSRFToken();
res.cookie('csrf',csrfToken);
res.redirect(url.format({
protocol: 'https',
hostname: 'www.dropbox.com',
pathname: '1/oauth2/authorize',
query: {
client_id: APP_KEY,
response_type: 'code',
state: csrfToken,
redirect_uri: generateRedirectURI(req)
}
}));
});
app.get('/callback', function(req, res) {
if(req.query.error) {
return res.send('ERROR ' + req.query.error + ': ' +
req.query.error_description);
}
if(req.query.state !== req.cookies.csrf) {
return res.status(401).send('CSRF token mismatch, possible' +
'cross-site request forgery attempt.'
);
}
request.post('https://api.dropbox.com/1/oauth2/token', {
form: {
code: req.query.code,
grant_type: 'authorization_code',
redirect_uri: generateRedirectURI(req)
},
auth: {
user: APP_KEY,
pass: APP_SECRET
}
}, function(error, response, body) {
var data = JSON.parse(body);
if(data.error)
return res.send('ERROR: ' + data.error);
var token = data.access_token;
console.log("Access token: " + token);
var fileName = "aai_success.pdf";
var options = {
hostname: 'content.dropboxapi.com',
port: 80,
path: '/1/files_put/auto/test.txt',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'multipart/form-data',
'Content-Length': 2,
'Transfer-Encoding': 'chunked'
},
strictSSL: false,
secureProtocol: 'SSLv3_method'
};
var rqst = https.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('BODY: ' + chunk);
});
});
rqst.write('AB');
rqst.end();
rqst.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
/*
var bts = 0;
fs.createReadStream(fileName).on('data', function(chunk) {
console.log("Got %d bytes from disk: ", chunk.length);
bts += bts + chunk.length;
var bytesSent = rqst.write(chunk);
console.log('Bytes sent: ' + bytesSent);
});
if(bts == 240519)
rqst.end();
*/
});
});
app.listen(3000, function() {
console.log('Application is running on port 3000');
});
You need to obtain a server certificate. You can self sign one for development using openssl (assuming you're on Linux) or you can obtain temporarily free ones. You also have the option to buy one from a certificate authority. Once you obtain a certificate look at the node.js docs under HTTPS or look at TLS (recommended) you can use their examples verbatim to setup SSL. https://nodejs.org/api/https.html
https://nodejs.org/api/tls.html
Solved the problem.
Change the port number to 443 and
remove the Content-Type header in options variable.
Didn't need to use strictSSL and secureProtocol
Didn't need to use SSL certificate.

express js cannot GET /page

I am very stuck with a routing error on express.js. I am using jade to render my page views. I have read all the docs and refactored many times to no avail.
This is the plain contents of the link that is pointing to the '/sell' route.
index.jade
include layout
html
button.btn.btn-primary(type='submit', href='/sell') Add Item
When clicking this button the browser returns the following as a 404:
Cannot GET /sell
The problem here is that all other routes work correctly, if you are to modify the above href to other pages i.e. '/' , '/sign_in', etc no error occurs. The problem appears to be isolated to the '/sell' route.
The controller with the '/sell' route is below:
server.js
var dotenv = require('dotenv');
dotenv.load();
var session = require('express-session')
var nodemailer = require('nodemailer');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt');
var async = require('async');
var crypto = require('crypto');
var cookieParser = require('cookie-parser');
var flash = require('express-flash');
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var root = __dirname;
var path = require('path');
var User = require('./models/user');
var bodyParser = require('body-parser');
var errorHelper = require('mongoose-error-helper').errorHelper;
var validator = require('validator');
var Item = require("./models/item")
var username, email, password, owner, product_name, condition, details, price;
mongoose.connect(process.env.MONGODB_CONGO_DEV);
// Middleware
app.set('views', 'app/views');
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(cookieParser());
app.use(session( {
secret: 'session secret key',
resave: false,
saveUninitialized: true
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
// Routing
app.get('/', function(req,res) {
res.render('index', {
title: 'Congo',
message: 'Congo',
user: req.user
});
});
app.get('/sell', function(req,res) {
res.render('item', {
title: 'Congo - Sell',
message: 'Sell',
user: req.user
});
});
app.get('/sign_in', function(req,res) {
res.render('sign_in', {
title: 'Congo',
message: 'sign in motherfucker',
user: req.user
});
});
app.post('/sign_in', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) return next(err)
if (!user) {
req.flash('error', 'Incorrect login details');
return res.redirect('/sign_in')
};
req.logIn(user, function(err) {
if (err) return next(err);
res.
return res.redirect('/');
});
})(req, res, next);
});
app.get('/sign_up', function(req, res) {
res.render('sign_up', {
title: 'Congo',
message: 'sign up',
user: req.user
});
});
app.post('/sign_up', function(req, res) {
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password
});
if (req.body.confirm != req.body.password) {
req.flash('error', 'Password do not match')
res.redirect('/sign_up')
};
else if (validator.isEmail(req.body.email) === false) {
req.flash('error', 'Invalid email address')
res.redirect('/sign_up')
};
else {
user.save(function(err) {
if (err) {
req.flash('error', 'Email already in use')
res.redirect('/sign_up')
} else {
req.logIn(user, function(err) {
res.redirect('/');
});
}
});
};
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.get('/forgot', function(req, res) {
res.render('forgot', {
user: req.user,
message: 'you wally'
});
});
app.get('/profile', function(req, res) {
res.render('profile', {
user: req.user,
message: 'User profile'
});
});
app.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/forgot');
};
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: 'harryandrew.dix#gmail.com',
pass: process.env.GMAIL_PASS
};
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
};
], function(err) {
if (err) return next(err);
res.redirect('/forgot');
});
});
app.get('/reset/:token', function(req,res) {
User.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now()}}, function(err,user) {
if (!user) {
req.flash('error', 'Password reset token invalid or expired.');
return res.redirect('/forgot');
}
res.render('reset', {
user: req.user,
message: 'reset dem pass'
});
});
});
app.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
};
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: 'harryandrew.dix#gmail.com',
pass: process.env.GMAIL_PASS
};
});
var mailOptions = {
to: user.email,
from: 'passwordreset#demo.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
};
], function(err) {
res.redirect('/');
});
});
// app.post('/add_item', function(req, res) {
// var item = new Item({
// owner: req.user.id,
// product_name: req.body.product_name,
// condition: req.body.condition,
// details: req.body.details,
// price: req.body.price
// });
// item.save(function(err) {
// if (err) {
// req.flash('error', 'Something went wrong, make sure you are signed in.')
// res.redirect('/add_item');
// } else {
// req.logIn(item, function(err) {
// res.redirect('/user_profile');
// });
// };
// });
// });
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s',host,port);
});
item.jade
include layout
html
block content
form(method='POST')
legend(style='font-family: Raleway; font-size: 30px;') Item Details
.form-group
label(for='product_name') Product Name
input.form-control(type='text', name='product_name', placeholder='include product name, brand, condition, colour etc.', required autofocus)
.form-group
label(for='condition') Condition
input.form-control(type='text', name='condition', placeholder='e.g. New, Used', required)
.form-group
label(for='image') Image
input.form-control(type='file', name='image')
.form-group
label(for='details') Details
textarea.form-control(name='details', cols='40', rows='5')
.form-group
label(for='price') Price
.input-group
.input-group-addon £
input.form-control(type='text', placeholder='Amount', required)
.input-group-addon .00
br
br
button#btnSubmit.btn.btn-primary(type='submit') Post Item
I think it's acting as form post and tries to reach app.post('/sell')
Change it:
button.btn.btn-primary(type='submit', href='/sell') Add Item
to:
a.btn.btn-primary(href='/sell') Add Item
also remove some parts of middleware and keep only these lines:
app.set('views', 'app/views');
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
and then navigate in Your browser to /sell route, check if it's working.
if Yes - so problem with one of middlewares that we have deleted to check.
You should add a logger middleware and see what error the server gives when you try to go to that route. Another thing to try would be to rename the sell route and see if that works. That could indicate a conflict with another one of your routes, although it's not clear where this would be from looking at your code.

Categories