Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Using dropboxjs to authenticate the client with oauth 2. What about the server?

Using dropboxjs to authenticate the client with oauth 2. What about the server?

Problem

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:

  • As soon as the client is authenticated, call my server and tell it that the user is authenticated
  • If the user doesn't exist on the server database, create an entry for it him/her the user database (I don't need detailed instructions to do this). If it exists, send back the user's associated data.

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?

Problem courtesy of: janesconference

Solution

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 = '';
var appsecret = '';

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);
Solution courtesy of: smarx

Discussion

View additional discussion.



This post first appeared on Node.js Recipes, please read the originial post: here

Share the post

Using dropboxjs to authenticate the client with oauth 2. What about the server?

×

Subscribe to Node.js Recipes

Get updates delivered right to your inbox!

Thank you for your subscription

×