I'm new to Oauth and server-side stuff, so please be patient with me.
I have a web application that authenticates users with dropbox-js. Everything is pretty straightforward. The application uses dropbox-js' client.authenticate
function, and if the user is authenticated, the application gets automatically redirected to the initial page, where it executes the authenticate callback. From that moment on, I know I'm happily authenticated with Dropbox, and I can do stuff with the app's Dropbox directory.
I got a public node.js server that currently does nothing. What I would like to do is:
How can I do that in a secure way? I mean, how can the server tell that the user is a valid Dropbox user? Should the server authenticate to Dropbox on its side with the user credentials? What is the workflow in these cases?
OAuth 2.0, which stands for “Open Authorization”, is a standard designed to allow a website or application to access resources hosted by other web apps on behalf of a user. It replaced OAuth 1.0 in 2012 and is now the de facto industry standard for online authorization.
A standard for user authentication using OAuth: OpenID Connect. OpenID Connect is an open standard published in early 2014 that defines an interoperable way to use OAuth 2.0 to perform user authentication.
OAuth doesn't share password data but instead uses authorization tokens to prove an identity between consumers and service providers. OAuth is an authentication protocol that allows you to approve one application interacting with another on your behalf without giving away your password.
It works by delegating user authentication to the service that hosts a user account and authorizing third-party applications to access that user account. OAuth 2 provides authorization flows for web and desktop applications, as well as mobile devices.
At the end of the authentication process, you have an access token, which is what's used to make calls to the API. If both the client and the server need to make calls to the API, then both will need to have the access token.
If you're doing the authentication client-side today, you could pull the access token out somehow (not sure if/how it's exposed from the library, but it's in there somewhere and also storaged in local storage) and pass it to the server. The server can then use it to call /account/info
and get the Dropbox user ID of the authenticated user.
An alternative is to do it the other way around. Authenticate the user with the "code flow" (rather than "token flow") and get the access token on the server in the first place. Then you could pass it down to the client and pass it as an option in the Dropbox.Client
constructor. I think that dropbox-js
supports this itself, but it's also not hard to do yourself. Here's some raw Express code that logs in a user and displays his or her name:
var crypto = require('crypto'),
express = require('express'),
request = require('request'),
url = require('url');
var app = express();
app.use(express.cookieParser());
// insert your app key and secret here
var appkey = '<your app key>';
var appsecret = '<your app secret>';
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'
});
}
app.get('/', function (req, res) {
var csrfToken = generateCSRFToken();
res.cookie('csrf', csrfToken);
res.redirect(url.format({
protocol: 'https',
hostname: 'www.dropbox.com',
pathname: '1/oauth2/authorize',
query: {
client_id: appkey,
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);
}
// check CSRF token
if (req.query.state !== req.cookies.csrf) {
return res.status(401).send(
'CSRF token mismatch, possible cross-site request forgery attempt.'
);
} else {
// exchange access code for bearer token
request.post('https://api.dropbox.com/1/oauth2/token', {
form: {
code: req.query.code,
grant_type: 'authorization_code',
redirect_uri: generateRedirectURI(req)
},
auth: {
user: appkey,
pass: appsecret
}
}, function (error, response, body) {
var data = JSON.parse(body);
if (data.error) {
return res.send('ERROR: ' + data.error);
}
// extract bearer token
var token = data.access_token;
// use the bearer token to make API calls
request.get('https://api.dropbox.com/1/account/info', {
headers: { Authorization: 'Bearer ' + token }
}, function (error, response, body) {
res.send('Logged in successfully as ' + JSON.parse(body).display_name + '.');
});
// write a file
// request.put('https://api-content.dropbox.com/1/files_put/auto/hello.txt', {
// body: 'Hello, World!',
// headers: { Authorization: 'Bearer ' + token }
// });
});
}
});
app.listen(8000);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With