Can't get Extended User Access Token from Facebook with OAuth2 NodeJS - node.js

I'd try to get Extended User Access Token from OAuth2 with Nodejs
Actually, the program send out a message (on Browser) with:
XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?redirect_uri=http%3A%2F%2Flocalhost%3…2Fcallback&scope=user_about_me%2Cpublish_actions&client_id=487932668044758. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Using standard express generator, I modified a code in a index.js as below:
var express = require('express');
var request = require('request');
var OAuth2 = require('oauth').OAuth2;
var router = express.Router();
var oauth2 = new OAuth2("487932668044758",
"0793918b3ab637b2096787e10643980a",
"", "https://www.facebook.com/dialog/oauth",
"https://graph.facebook.com/oauth/access_token",
null);
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', {
// title: 'Express'
});
});
router.post('/userToken', function(req, res) {
if (!req.body) {
return
res.sendStatus(400)
}
var uid = req.body.uid;
var token = req.body.token;
validate_uid_token(uid, token, res);
console.log('req:', req.body);
console.log("uid: ", uid);
console.log('token: ', token);
// res.send("okie");
});
router.get("/callback", function(req, res) {
console.log('here..form callback');
res.header('Access-Control-Allow-Origin', 'http://localhost3000');
res.header('Access-Control-Allow-Origin', 'https://www.facebook.com/dialog/oauth');
res.header('Access-Control-Allow-Origin', 'https://graph.facebook.com/oauth/access_token');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
if (req.error_reason) {
res.send(req.error_reason);
}
if (req.query.code) {
var loginCode = req.query.code;
var redirect_uri = "/"; // Path_To_Be_Redirected_to_After_Verification
// For eg. "/facebook/callback"
oauth2.getOAuthAccessToken(loginCode, {
grant_type: 'authorization_code',
redirect_uri: redirect_uri
},
function(err, accessToken, refreshToken, params) {
if (err) {
console.error(err);
res.send(err);
return;
}
var access_token = accessToken;
console.log('access_token : ', access_token);
// var expires = params.expires;
// console.log('expires : ', expires);
req.session.access_token = access_token;
// req.session.expires = expires;
}
);
}
// res.send('okie');
});
function validate_uid_token(uid, token, res) {
var redirect_uri = "http://localhost:3000" + "/callback";
// For eg. "http://localhost:3000/facebook/callback"
var params = {
'redirect_uri': redirect_uri,
'scope': 'user_about_me,publish_actions'
};
res.redirect(oauth2.getAuthorizeUrl(params));
}
module.exports = router;
Click on a url in error message. Browser throws out ma JSON message as
{"statusCode":400,"data":"{\"error\":{\"message\":\"redirect_uri isn't an absolute URI. Check RFC 3986.\",\"type\":\"OAuthException\",\"code\":191}}"}
Could someone help me please...Thank to much..

I'd recommend to use Passport.js together with the passport-facebook strategy. This hides away most of the complexity involved.
See
http://passportjs.org/
https://github.com/jaredhanson/passport-facebook

Related

Cannot read property 'hashedPassword' of undefined

This is the code for the "login" process and I want to return a "token", but when I send the request I see this error, How can I solve it
in Console (with the Error):
LogIn
, NourGeorge#gmail.com
, 1923552
,✖ TypeError: Cannot read property 'hashedPassword' of undefined
, POST /user/login 401 48.376 ms - 87
I send This request from postman:
POST http://localhost:4000/user/login
Content-Type: application/json
{
"email":"NourGeorge#gmail.com",
"password":"1923552"
}
I get this answer from Postman:
{
"accessToken": null,
"message": "User login error,Invalid Information(Invalid Password)"
}
userController.js:
////Login
const login = async (req, res, next) => {
console.log('LogIn');
let { email, password } = req.body;
console.log(email)
console.log(password);
// in findUserByEmail Compaire password with password in database
const result = await User.findUserByEmail(email, password);
//if the password is correct => generate a token using JWT
if (result == 1) {
res.status(200).json({
message: 'Process succeeded'
});
// generate a token using JWT
const accessToken = jwt.sign({ id: user.uid }, process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: 3600 //1 hour
})
// res.json({accessToken:accessToken})
// return user information & access token
res.status(200).send({
id: user.uid,
email: user.email,
// password: user.password,
accessToken: accessToken
})
}
else {
res.status(401).json({
accessToken: null,
message: 'User login error,Invalid Information(Invalid Password)'
// error: 'User login error,Invalid Information(Invalid Password)'
});
}
}
userModel.js:
static async findUserByEmail(email, password) {
const Log_I=await SingletonSqlHandler.instance.sendQuery(`SELECT * FROM
GetUserByEmail('${email}')`)
.then(result => {
let userData = result.recordset[0];
const areMatched = PasswordHasher.verify(password, userData.hashedPassword);
if (areMatched) {
Printer.Logger.print("Successfully logged in", Printer.Colors.green,
Printer.Symbols.ok, true);
return 1;
} else {
Printer.Logger.print('Password is incorrect', Printer.Colors["error message"],
Printer.Symbols.err, true);
}
return 0;
}).catch(err => {
Printer.Logger.print("" + err, Printer.Colors["error message"], Printer.Symbols.err,
true);
return -1;
});
return Log_I;
}
}
userRouter.js:
const router = require('express').Router();
const userController = require('../Controllers/userController');
router.post('/login',userController.login);
module.exports = router;
app.js:
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const https=require('https');
const request=require('request');
// Modules Variable
const app = express();
// User import
const usersRoutes = require('./routes/userRoute');
const productsRoutes=require('./routes/productRoute')
app.use(express.json())
app.use(morgan('dev')); // Logger middleware
app.use(bodyParser.urlencoded({extended: false})); // Parsing body middleware
app.use(bodyParser.json({limit: '500mb'})); // Parsing JSON objects
// Adding headers
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // Allowing reqeusts from everywhere
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept,
Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});
// Detecting routes
app.use('/user', usersRoutes);
app.use('/product', productsRoutes);
// Handling invalid routes
app.use((req, res, next) => {
const error = new Error('Not found');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
module.exports = app;

Digest auth using http-auth

Trying to implement Digest auth in nodejs. Below is the code
var http = require('http');
var auth = require('http-auth');
var express = require('express');
var app = express();
var user;
var basic = auth.basic({
realm: 'Sample',
file: __dirname + "/users.htpasswd",
algorithm:'md5'
});
basic.on('success', (result, req) => {
console.log(`User authenticated: ${result.user}`);
user = result.user;
});
basic.on('fail', (result, req) => {
console.log(`User authentication failed: ${result.user}`);
console.log(req.headers.authorization);
});
basic.on('error', (error, req) => {
console.log(`Authentication error: ${error.code + " - " + error.message}`);
});
http.createServer(app).listen(8000);
app.use(auth.connect(basic));
app.get('/', function(req, res) {
console.log(req.headers);
console.log(basic);
res.json('Hello from '+ user);
res.end();
});
app.post('/', function(req, res) {
console.log(req.headers);
console.log(basic);
res.json('Hello from '+ user);
res.end();
});
This is the content of users.htpasswd file:-
ankit:Sample:e4b2d19b03346a1c45ce86ad41b85c5e
Using postman to call the end point with username ankit, pwd ankit & realm Sample, everytime I am getting 401.
Please let me know where I am doing wrong.
Thanks
You're mixing basic auth and digest auth. Replace auth.basic with auth.digest and your code should work as-is.

ExpressJS authorization middleware get executed even for the routes above it

I am working on a university/student project with full MEAN stack. We have NodeJS, ExpressJS backend and Angular2 frontend. Backend runs on localhost:8080 and frontend runs on localhost:4200
This is how my backend looks like
var express = require('express'),
...
var app = express();
...
// needed because of cross origin resource sharing during development
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
var port = process.env.PORT || 8080;
var loginController = require('./controllers/loginController')(Person);
var personController = require('./controllers/personController')(Person, Transaction);
var transactionController = require('./controllers/transactionController')(Person, Transaction);
var apiRouter = express.Router();
apiRouter.post('/login', loginController.authenticate);
/**
* Middleware that handles authorization of particular routes.
* Every request which starts with `/api/persons` or `/api/transactions`, will be intercepted and validated against JWT.
*/
apiRouter.use(function (req, res, next) {
// JWT gets validated
});
apiRouter.get('/persons', personController.fetchAllPersons);
apiRouter.get('/persons/:personId', personController.fetchPersonById);
apiRouter.get('/persons/:personId/transactions', personController.fetchTransactionsByPersonId);
apiRouter.post('/transactions', transactionController.addNewTransaction);
app.use('/api', apiRouter);
app.listen(port, function () {
console.log('Listening on port: ' + port);
});
I read that the routes of the express router get executed sequentially, so the order of middleware inclusion is important. Therefore I set it after /login route since it should not be available without JWT authorization.
When I start the application and execute requests with postman everything works as it is supposed, but when I try to login from the frontend middleware function gets executed also for login route but it shouldn't, right?
Is is maybe because of they are running on different ports or could it be an issue caused by cross origin, I really have no idea?
Did anyone already face similar issue and could you please explain this behavior?
Thx
EDIT 1:
As robertklep has mentioned below, it might depend on the loginController implementation and the way how we handle login in frontend, here are the code snippets
jwt = require('jsonwebtoken');
var loginController = function (Person) {
var authenticate = function (req, res) {
req.person = req.body;
var searchPerson = { username: req.person.username }
Person.findOne(searchPerson, function (err, person) {
if (err) throw err;
if (!person) {
return res.status(401).send({ message: 'Wrong username/password' });
}
person.comparePasswords(req.person.password, function (err, isMatch) {
if (err) throw err;
if (!isMatch) {
return res.status(401).send({ message: 'Wrong username/password' });
}
var token = jwt.sign(person._id, /* XXX SECRET XXX */);
res.status(200).json({
token: token,
person: person
});
});
});
};
return {
authenticate: authenticate
};
};
module.exports = loginController;
Frontend:
...
export class LoginComponent implements OnInit {
/**
* validates input data and on successful validation,
* tries to login the user with her/his credentials
*/
public login(): void {
// validation logic should consider all fields, no matter if the user has entered any data
this.validate(false);
// no validation error, continue with login process
if(!this.errorMessage){
const form = this.loginForm;
var credentials = {
name: form.get('name').value,
password: form.get('password').value
};
this.loginService.login(credentials.name,credentials.password)
.subscribe(
name => this.router.navigate(['welcome']),
error => this.errorMessage = error);
}
}
}
...
export class LoginService {
...
public login(userName: string, password: string): Observable<string> {
var person = {
'username': userName,
'password': password
};
return this.http.post('http://localhost:8080/api/login',person)
.map(this.extractToken)
.catch(this.handleError);
}
}
EDIT 2:
As asked, I am posting my middleware, so this is how it looks like
apiRouter.use(function(req, res, next) {
// first, check if a token is provided
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
// token gets validated by jwt lib
jwt.verify(token, /* SECRET */, function (err, decoded) {
if (err) {
// token invalid, respond with unauthorized
res.status(401).json({
message: 'Failed to authenticate token.'
});
} else {
// token is valid, continue to the particular request handler
req.decoded = decoded;
next();
}
});
} else {
// token was not provided, respond with forbidden
res.status(403).json({
message: 'No token provided.'
});
}
});
Like I said, when I use postman client and execute login request, everything works as expected (Middleware doesn't execute for the login request) but when I start our frontend app and do the same, middleware function gets executed.

express-jwt Not respecting unprotected paths

Information on the express-jwt module can be found here:
https://github.com/auth0/express-jwt
https://www.npmjs.com/package/express-jwt
In my main.js server file, I have the following:
import ExpressJwt from 'express-jwt';
// import other crap...
let token = ExpressJwt({
secret: 'whatever',
audience: 'whatever',
issuer: 'whatever'
});
app.all('/apiv1', token.unless({ path: ['apiv1/user/create', '/apiv1/auth/login']}));
app.use('/apiv1/user', user);
app.use('/apiv1/auth', auth);
Where user and auth are the middlewares that handle my routes. What I want to do is obvious; deny API access to all unauthenticated users, except when they attempt to create a new user via apiv1/user/create and/or login via apiv1/auth/login.
Any time I try to make a request to the aforementioned unprotected paths however, I get the error:
UnauthorizedError: No authorization token was found
It's still protecting the routes I specified to be unprotected! I also tried:
app.use('/apiv1/user', token.unless({ path: ['/apiv1/user/create'] }), user);
app.use('/apiv1/auth', token.unless({ path: ['/apiv1/auth/login'] }), auth);
But that didn't work. I also tried using regex for the unless paths, but that didn't work either.
I arrived at app.all('/apiv1', token...) via this answer, but that solution does not yield me the desired functionality.
Instead of using all:
app.all('/apiv1', token.unless({ path: ['apiv1/user/create', '/apiv1/auth/login']}));
Try using use and adding in the path route a slash / at the beginning:
app.use('/apiv1', token.unless({ path: ['/apiv1/user/create', '/apiv1/auth/login']}));
Here it is an example that is working:
app.js:
var express = require('express');
var app = express();
var expressJwt = require('express-jwt');
var jwt = require('jsonwebtoken');
var secret = 'secret';
app.use('/api', expressJwt({secret: secret}).unless({path: ['/api/token']}));
app.get('/api/token', function(req, res) {
var token = jwt.sign({foo: 'bar'}, secret);
res.send({token: token});
});
app.get('/api/protected', function(req, res) {
res.send('hello from /api/protected route.');
});
app.use(function(err, req, res, next) {
res.status(err.status || 500).send(err);
});
app.listen(4040, function() {
console.log('server up and running at 4040 port');
});
module.exports = app;
test.js:
var request = require('supertest');
var app = require('./app.js');
describe('Test API', function() {
var token = '';
before(function(done) {
request(app)
.get('/api/token')
.end(function(err, response) {
if (err) { return done(err); }
var result = JSON.parse(response.text);
token = result.token;
done();
});
});
it('should not be able to consume /api/protected since no token was sent', function(done) {
request(app)
.get('/api/protected')
.expect(401, done);
});
it('should be able to consume /api/protected since token was sent', function(done) {
request(app)
.get('/api/protected')
.set('Authorization', 'Bearer ' + token)
.expect(200, done);
});
});

Google+ Domains 403 Forbidden when listing circles

This is the source code that requests the permissions and try to list the circles,
What I want to make is to be able to list the circle's person, add/remove people from the circles but I get a forbidden error when I try to do it, and I get the access to those scopes.
var express, router, nconf, OAuth2, oauth2Client, scopes, google;
scopes = [
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/plus.circles.read',
'https://www.googleapis.com/auth/plus.circles.write'
];
google = require('googleapis')
nconf = require('nconf');
OAuth2 = google.auth.OAuth2;
express = require('express');
router = express.Router();
oauth2Client = new OAuth2(CLIENT_ID, SECRET_ID, REDIRECT_URL);
router.get('/', function(req, res) {
var url = oauth2Client.generateAuthUrl({
access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
scope: scopes // If you only need one scope you can pass it as string
});
res.redirect(url);
});
router.get('/auth', function(req, res) {
console.log("code >> " + req.query.code);
oauth2Client.getToken(req.query.code, function(err, tokens) {
if(!err) {
console.log("TOKENS >> " + JSON.stringify(tokens));
oauth2Client.setCredentials(tokens);
var plusDomains = google.plusDomains('v1');
plusDomains.circles.list({ userId: 'me', auth: oauth2Client }, function(err, circles) {
console.log('Result circles: ' + (err ? err.message : JSON.stringify(circles)));
});
}
res.send({tokens: tokens});
});
});
module.exports = router;

Resources