I have a web application using OAuth 2 running on Node. Using EJS templates, I was able to correctly create a workflow that prompts the user to log in, authenticate and then execute the βGetUserβ GET command and upload the output to the screen. I recently tried uninstalling EJS and want AnguarJS to work.
I have currently uninstalled EJS and implemented Angular, however many strange things have happened to angular, and I cannot understand why!
When my user clicks "Login", they are supposed to be delivered to another website where they use OAuth 2. This process works fine on Node with EJS, however with angular my controller loads, loads, but no data. Having examined this process using Chrome DEV tools, I see the following error:
XMLHttpRequest cannot load http://website/oauth/authorize?... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
What's even weirder is that on the network tab, I see the correct request URL! If I copy and paste this URL into another tab, my "GetUser" command is executed, but then Node crashes and my page crashes.
I tried using various browsers by enabling CORS and configuring CORS. I know the problem is with angular, as I can successfully use the same code with EJS. I put the angular code below, any help would be appreciated!
Server side
app.js
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var config = require('./config.js') var passport = require('passport'); var OAuth2Strategy = require('passport-oauth').OAuth2Strategy; var session = require('express-session'); var index = require('./routes/index'); var login = require('./routes/login'); var logout = require('./routes/logout'); passport.serializeUser(function(user, done) {done(null, user); }); passport.deserializeUser(function(obj, done) {done(null, obj); }); // config passport.use('Company', new OAuth2Strategy({ authorizationURL: config.authorizationURL, tokenURL: config.tokenURL, clientID: config.clientID, clientSecret: config.clientSecret, callbackURL: config.callbackURL, passReqToCallback: true }, function(req, accessToken, refreshToken, profile, done) { process.nextTick(function () { // store access token req.session.accessToken=accessToken; return done(null, profile); }); } )); var app = express(); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use(session({secret: 'secret'})) app.use(passport.initialize()); app.use(passport.session()); // configure Express app.get('/api/login', ensureAuthenticated, login.execute); app.get('/api/logout', logout.execute); app.get('/auth/company', passport.authenticate('company'), function(req, res){ }); app.get('/auth/company/callback', passport.authenticate('company', { failureRedirect: '/' }), function(req, res) { console.log('comming back from company'); res.redirect('/api/login'); }); app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); function ensureAuthenticated(req, res, next) { if (req.isAuthenticated()) { return next(); } res.redirect('/') } module.exports = app;
Login.js (Route)
var request = require('request'); exports.execute = function (req, res) { console.log(req.user); console.log(req.app.get('accessToken')); var accessToken = req.session.accessToken; console.log("accessToken in loginjs" + accessToken); if(accessToken){ var options = { url: 'http://company/getCurrentUser', headers: { Authorization: 'bearer ' + accessToken } }; request.get(options, function(error, response, body){ if(error){ console.log('login.js inside error' + error); res.json('login.js inside error' + error); return; } console.log(response); res.render('account', { user: response }); }); }else{ res.render('account', { user: req.user }); } }
WWW
var debug = require('debug')('myApp'); var app = require('../app'); app.set('port', process.env.PORT || 8080); var server = app.listen(app.get('port'), function() { debug('Express server listening on port ' + server.address().port); });
Client side
app.js (angular) ##
angular.module('MyApp', ['ngCookies', 'ngResource', 'ngMessages', 'ngRoute', 'mgcrea.ngStrap']) .config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { $locationProvider.html5Mode(true); $routeProvider .when('/', { templateUrl: 'views/home.html', controller: 'MainCtrl' }) .when('/login', { templateUrl: 'views/account.html', controller: 'LoginCtrl' }) .otherwise({ redirectTo: '/' }); }]);
login.js controller
angular.module('MyApp') .controller('LoginCtrl', ['$scope', 'Auth', function($scope, Auth){ var user = Auth.authorize(); $scope.user=user; $scope.headingTitle='Logged in page'; }]);
auth.js Service
angular.module('MyApp') .factory('Auth', ['$resource', function($resource){ return $resource('/auth/company', null, { 'authorize': {method: 'GET'} }); }]);
home.html Partially route to Oauth2
<div class="container"> <div class="panel panel-default"> <div class="panel-body"> <div class="text-center"> <p><a href="/login">Login via Company</a></p> </div> </div> </div> </div>
account.html Partial display of user data
<div> <h1>You are logged in.</h1> <a href="/">Go home</a><br> <a href="/api/logout">Logout</a><br> <p>Dumping User: {{user}}</p> </div>
change
I tried to follow without success
var allowCrossDomain = function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X- Requested-With, Access-Control-Allow-Origin'); res.header("Access-Control-Max-Age", "86400"); // 24 hours if ('OPTIONS' == req.method) { res.send(200); } else { next(); } }; var app = express(); app.use(allowCrossDomain);
Edit 2:
I did some more digging, and also noticed that angular is not listed as the initiating second URL. Its almost as if angular redirects the callback url as a separate native call. I have attached the image below
Edit 3:
I continued to work on this, but can't figure out why angular removes my headers! Any additional input would be greatly appreciated!
Change 4:
I found that on the web page you can load the route instead of angular by adding the code below to the "Login" button. After that, and pointing to the link to / auth / company, and not to api / login, I am successfully redirected to the login page!
<div class="container"> <div class="panel panel-default"> <div class="panel-body"> <div class="text-center"> <p><a target="_self" href="/auth/company">Login via Company</a></p> </div> </div> </div> </div>
However, the battle continues, since after entering the system I am redirected to the image below - inside Node I get data, but the application dies and does not show the / account page.