{"action":"created","issue":{"url":"https://api.github.com/repos/driftyco/ionic/issues/3327","labels_url":"https://api.github.com/repos/driftyco/ionic/issues/3327/labels{/name}","comments_url":"https://api.github.com/repos/driftyco/ionic/issues/3327/comments","events_url":"https://api.github.com/repos/driftyco/ionic/issues/3327/events","html_url":"https://github.com/driftyco/ionic/issues/3327","id":61951305,"number":3327,"title":"docs: How to send CSRF information  to the server?","user":{"login":"mzarella","id":10657689,"avatar_url":"https://avatars.githubusercontent.com/u/10657689?v=3","gravatar_id":"","url":"https://api.github.com/users/mzarella","html_url":"https://github.com/mzarella","followers_url":"https://api.github.com/users/mzarella/followers","following_url":"https://api.github.com/users/mzarella/following{/other_user}","gists_url":"https://api.github.com/users/mzarella/gists{/gist_id}","starred_url":"https://api.github.com/users/mzarella/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzarella/subscriptions","organizations_url":"https://api.github.com/users/mzarella/orgs","repos_url":"https://api.github.com/users/mzarella/repos","events_url":"https://api.github.com/users/mzarella/events{/privacy}","received_events_url":"https://api.github.com/users/mzarella/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-03-16T02:58:38Z","updated_at":"2015-03-17T01:36:28Z","closed_at":null,"body":"**Type**: <span ionic-type>docs</span>\r\n\r\n**Platform**: <span ionic-platform>mobile</span>  <span ionic-webview>browser</span>\r\n\r\n<span ionic-description>I am using oauth-phonegap to handle authentication. It seems to have gotten me to a decent point in prototyping, but I now need it to actually authenticate the user on my server.  I am CCing @william26, whom I believe is the maintainer of oauth-phonegap and @dougwilson, whom I believe is the maintainer of the express middleware csurf. I am using both of these technologies they are actively involved in. I'm opening this up as an ionic issue, because I have yet to see documentation on handling authentication, and it would be nice for the community to have this available as a resource. I think, also, that this conversation might help steer any documentation that may come from this.\r\n\r\n**Update:** looks like there is a blog post on this subject:\r\nhttp://ionicframework.com/blog/angularjs-authentication/\r\nSo maybe now this is hopefully more of a resource for someone else who may be experiencing similar difficulties.\r\n\r\nI'm wondering how you ensure proper csrf information is sent to the server. Currently my login controller looks like this:\r\n\r\n```js\r\n  var app = angular.module('app');\r\n\r\n  app.controller('LoginCtrl', function($scope, $state, UserService, $http, $cookies) {\r\n    OAuth.initialize('LONG_STRING');\r\n    var token = null;\r\n    // fetch csrf session token from server\r\n    $http.get('http://api.example.com/oauth/token')\r\n    .success(function(generatedToken, status) {\r\n      return token = generatedToken;\r\n    }).error(function(errorMessage, status) {\r\n      return console.log(\"l8 LoginCtrl\\n \" + status + \": \" + errorMessage);\r\n    });\r\n\r\n    // fired when user touches the Google login button\r\n    $scope.googleLogin = function() {\r\n      return OAuth.popup('google', {\r\n        cache: false,\r\n        state: token\r\n      }).done(function(result) {\r\n        // so far so good, but this is where the request is invalid\r\n        $http.post(\"http://api.example.com/oauth/signin\")\r\n        .success(function(data, status) {\r\n          debugger;\r\n        }).error(function(data, status) {\r\n          debugger;\r\n        });\r\n      }).fail(function(error) {\r\n        return console.log('error: ', error);\r\n      });\r\n    };\r\n```\r\n\r\nIt's when I send a POST request to /oauth/signin that my server is unhappy:\r\n`ForbiddenError: invalid csrf token`\r\n\r\n\r\nMy express server code looks like this:\r\n\r\n```js\r\n var MongoStore, app, bodyParser, compress, connectAssets, cookieParser, csrf, csrfProtection, errorHandler, express, expressValidator, flash, logger, methodOverride, mongoose, multer, oauth, passport, passportConf, parseForm, path, secrets, session;\r\n\r\n  express = require('express');\r\n  cookieParser = require('cookie-parser');\r\n  compress = require('compression');\r\n  session = require('express-session');\r\n  bodyParser = require('body-parser');\r\n  logger = require('morgan');\r\n  errorHandler = require('errorhandler');\r\n  methodOverride = require('method-override');\r\n  multer = require('multer');\r\n  MongoStore = require('connect-mongo')(session);\r\n  flash = require('express-flash');\r\n  path = require('path');\r\n  mongoose = require('mongoose');\r\n  passport = require('passport');\r\n  expressValidator = require('express-validator');\r\n  connectAssets = require('connect-assets');\r\n  csrf = require('csurf');\r\n  oauth = require('oauthio');\r\n  oauth.initialize('NE4HoArIyEc1uI70v5RZ5wIkM1U', '7Ow9lx7rfR6f5mrZDOyZebjw9fc');\r\n\r\n  csrfProtection = csrf({\r\n    cookie: true\r\n  });\r\n\r\n  parseForm = bodyparser.urlencoded({ extended: false })\r\n\r\n  secrets = require('./config/secrets');\r\n  passportConf = require('./config/passport');\r\n\r\n  app = express();\r\n\r\n  mongoose.connect(secrets.db);\r\n\r\n  mongoose.connection.on('error', function() {\r\n    console.error('MongoDB Connection Error. Please make sure that MongoDB is running.');\r\n  });\r\n\r\n  app.set('port', process.env.PORT || 3000);\r\n  app.set('views', path.join(__dirname, 'views'));\r\n  app.set('view engine', 'jade');\r\n  app.use(compress());\r\n\r\n  app.use(connectAssets({\r\n    paths: [path.join(__dirname, 'public/css'), path.join(__dirname, 'public/js')]\r\n  }));\r\n\r\n  app.use(logger('dev'));\r\n  app.use(bodyParser.json());\r\n\r\n  app.use(multer({\r\n    dest: path.join(__dirname, 'uploads')\r\n  }));\r\n\r\n  app.use(expressValidator());\r\n  app.use(methodOverride());\r\n  app.use(cookieParser());\r\n\r\n  app.use(session({\r\n    resave: true,\r\n    saveUninitialized: true,\r\n    secret: secrets.sessionSecret,\r\n    store: new MongoStore({\r\n      url: secrets.db,\r\n      autoReconnect: true\r\n    })\r\n  }));\r\n\r\n  app.use(passport.initialize());\r\n  app.use(passport.session());\r\n  app.use(flash());\r\n\r\n  app.use(express[\"static\"](path.join(__dirname, 'public'), {\r\n    maxAge: 31557600000\r\n  }));\r\n\r\n  app.use(csrf(), function(req, res, next) {\r\n    debugger;\r\n    res.cookie('csrf-token', req.csrfToken());\r\n    return next();\r\n  });\r\n\r\n  app.get('/oauth/token', csrfProtection, function(req, res) {\r\n    var token;\r\n    token = oauth.generateStateToken(req.session);\r\n    return res.send(token);\r\n  });\r\n\r\n  app.post(\"/oauth/signin\", parseForm, csrfProtection, function(req, res) {\r\n    var code = req.body.data;\r\n    debugger;\r\n    oauth.auth(\"google\", req.session, {\r\n      code: code\r\n    }).then(function(request_object) {\r\n      debugger;\r\n      return res.send(200, \"The user is authenticated\");\r\n    }).fail(function(e) {\r\n      debugger;\r\n      console.log(e);\r\n      return res.send(400, \"Code is incorrect\");\r\n    });\r\n    return res.redirect(req.session.returnTo || '/');\r\n  });\r\n\r\n  app.use(errorHandler());\r\n\r\n  app.listen(app.get(\"port\"), function() {\r\n    console.log(\"Express server listening on port %d in %s mode\", app.get(\"port\"), app.get(\"env\"));\r\n  });\r\n\r\n  module.exports = app;```\r\n```\r\n\r\nAnd here's the error code:\r\n\r\n```\r\nroot@example:~/example-api# node index\r\nExpress server listening on port 3000 in development mode\r\nGET /oauth/token 200 25.549 ms - 26\r\nForbiddenError: invalid csrf token\r\n  at verifytoken (/root/example-api/node_modules/csurf/index.js:263:11)\r\n  at csrf (/root/example-api/node_modules/csurf/index.js:93:7)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at serveStatic (/root/example-api/node_modules/express/node_modules/serve-static/index.js:59:14)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at /root/example-api/node_modules/express-flash/lib/express-flash.js:31:7\r\n  at /root/example-api/node_modules/express-flash/node_modules/connect-flash/lib/flash.js:21:5\r\n  at /root/example-api/node_modules/express-flash/lib/express-flash.js:22:5\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at SessionStrategy.strategy.pass (/root/example-api/node_modules/passport/lib/middleware/authenticate.js:318:9)\r\n  at SessionStrategy.authenticate (/root/example-api/node_modules/passport/lib/strategies/session.js:67:10)\r\n  at attempt (/root/example-api/node_modules/passport/lib/middleware/authenticate.js:341:16)\r\n  at authenticate (/root/example-api/node_modules/passport/lib/middleware/authenticate.js:342:7)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at initialize (/root/example-api/node_modules/passport/lib/middleware/initialize.js:62:5)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at session (/root/example-api/node_modules/express-session/index.js:386:7)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at cookieParser (/root/example-api/node_modules/cookie-parser/index.js:34:14)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at methodOverride (/root/example-api/node_modules/method-override/index.js:77:5)\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at /root/example-api/node_modules/express-validator/lib/express_validator.js:233:12\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at /root/example-api/node_modules/multer/index.js:218:19\r\n  at Layer.handle [as handle_request] (/root/example-api/node_modules/express/lib/router/layer.js:82:5)\r\n  at trim_prefix (/root/example-api/node_modules/express/lib/router/index.js:302:13)\r\n  at /root/example-api/node_modules/express/lib/router/index.js:270:7\r\n  at Function.proto.process_params (/root/example-api/node_modules/express/lib/router/index.js:321:12)\r\n  at next (/root/example-api/node_modules/express/lib/router/index.js:261:10)\r\n  at /root/example-api/node_modules/body-parser/lib/read.js:111:5\r\n  at IncomingMessage.onEnd (/root/example-api/node_modules/body-parser/node_modules/raw-body/index.js:136:7)\r\n  at IncomingMessage.g (events.js:180:16)\r\n  at IncomingMessage.EventEmitter.emit (events.js:92:17)\r\n  at _stream_readable.js:920:16\r\n  at process._tickCallback (node.js:415:13)\r\n\r\nPOST /oauth/signin 403 39.044 ms - -\r\n```\r\n\r\nI'm at a stopping point on this tonight and could use some suggestions. Thank you all for your patience and hard work!</span>\r\n\r\n<span is-issue-template></span>\r\n"},"comment":{"url":"https://api.github.com/repos/driftyco/ionic/issues/comments/82023025","html_url":"https://github.com/driftyco/ionic/issues/3327#issuecomment-82023025","issue_url":"https://api.github.com/repos/driftyco/ionic/issues/3327","id":82023025,"user":{"login":"mzarella","id":10657689,"avatar_url":"https://avatars.githubusercontent.com/u/10657689?v=3","gravatar_id":"","url":"https://api.github.com/users/mzarella","html_url":"https://github.com/mzarella","followers_url":"https://api.github.com/users/mzarella/followers","following_url":"https://api.github.com/users/mzarella/following{/other_user}","gists_url":"https://api.github.com/users/mzarella/gists{/gist_id}","starred_url":"https://api.github.com/users/mzarella/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzarella/subscriptions","organizations_url":"https://api.github.com/users/mzarella/orgs","repos_url":"https://api.github.com/users/mzarella/repos","events_url":"https://api.github.com/users/mzarella/events{/privacy}","received_events_url":"https://api.github.com/users/mzarella/received_events","type":"User","site_admin":false},"created_at":"2015-03-17T01:36:28Z","updated_at":"2015-03-17T01:36:28Z","body":"I've updated the snippets in the first post. It's still issuing the same error, but hopefully it's all _slightly_ more readable. \r\n\r\nThis is what is happening:\r\n\r\n1. The ionic app (henceforth: *client*) requests an oauth session token by sending a GET request to `/oauth/token`\r\n\r\n2. On the server, `oauth.generateStateToken(req.session)` generates this token and sends it back to the client. This is but one of the CSRF tokens, the others being generated by csurf.\r\n\r\nI don't think the oauth CSRF token generation is the problem right now.\r\n\r\n@dougwilson \r\nThank you for being so responsive! Right now, I don't know when exactly the csurf module generates the csrf token and sends it back to the client. So, I'm guessing the problem is that the client doesn't have the csrf token generated by csurf, and as a result of not having a clear picture of what's going on, I'm most likely not sending the csrf token back to the server. When is csurf generating the csrf token, and how is it being sent back to the client (e.g. in a header, as a cookie)?\r\n\r\nOne the client side, I have added the following snippets as suggested by @mlynch in his [Cookie-based Authentication in AngularJS](http://ionicframework.com/blog/angularjs-authentication/) post. \r\n\r\nIn app.config, this is set:\r\n\r\n```js\r\n  // use cookies!\r\n  $httpProvider.defaults.withCredentials = true\r\n  // name of the csrf cookie\r\n  $httpProvider.defaults.xsrfCookieName = '_csrf'\r\n```\r\n\r\nIn app.run, this is set:\r\n```js\r\n  // set the name of the token in the header to 'csrf-token' and its value being the cookie named \"_csrf\"\r\n  $http.defaults.headers.post['csrf-token'] = $cookies._csrf\r\n```\r\n\r\nAt which point does csurf generate a csrf token."}}