OAuth Server side Node.js examples

From OpenStreetMap Wiki
Jump to navigation Jump to search

See the full, detailed and more updated example here: https://maartenvandenhoven.com/blog/using-oauth-1-0a-server-side-in-node-js/

Using OAuth on the client side exposes the keys and secrets of both the consumer and the user, which is a security risk. This page displays the OAuth process on the server side using Node.js. The examples below make use of the request package. Error handling is not included in these examples.

Step one: Get an oauth token and oauth secret and generate a URL that will be used to start the user authorization process. The req object is from the request that the user sends from the client to the Node.js server. We use this to save the response data in the user's session.

request.post({
    url: "https://www.openstreetmap.org/oauth/request_token", 
    oauth: {
        callback: "https://YOURWEBSITE.COM/api/oauth/callback", // Supply a callback url. OSM uses the callback url later to return the key data to your application/website.
        consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Consumer key and secret are given to the developer after registering the application on the official OSM site.
        consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    }
}, (err, rs, body) => {
    var bodyObject = qs.parse(body); // You can use the querystring package (const qs = require("querystring");) to parse the data to a javascript object.
    req.session.oauth_token = bodyObject.oauth_token; // Put the token and token secret in the session of this user.
    req.session.oauth_token_secret = bodyObject.oauth_token_secret;
    res.send("https://www.openstreetmap.org/oauth/authorize?oauth_token=" + bodyObject.oauth_token); // This URL is used by the user to authorize. Send it to the client so that the client can use it. You could open a popup window or new tab with this URL so that the user can authorize on the official OSM site.
});


Step two: After the user uses the previously mentioned popup window or new tab to authorize itself on the official OSM website the OSM server will send a request to the previously supplied callback URL. Make a route for this callback URL and then finish the OAuth process by making a final OAuth request to get the access token and secret. These will be used to make requests to the OSM API later on.

request.post({
    url: "https://www.openstreetmap.org/oauth/access_token", 
    oauth: {
        consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Supply the consumer key, consumer secret, access token and access secret for every request to the API.
        consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        token: req.query.oauth_token, 
        token_secret: req.session.oauth_token_secret,
        verifier: req.query.oauth_verifier // The OSM callback contains this verifier. You need it to finalize the OAuth authentication process.
    }
}, (err, rs, body) => {
    var bodyObject = qs.parse(body);
    req.session.access_token = bodyObject.oauth_token; // Save the access token and access secret in the user's session.
    req.session.access_token_secret = bodyObject.oauth_token_secret;
    res.sendFile(global.appRoot + "/public/land.html"); // What you do here depends on how you build your front-end. I return a landing page that closes itself and calls a function on the client side.
});


Step three: You're ready to start sending requests to the OSM API. Here is an example of receiving user details of the authorized user.

request({
    url: "https://www.openstreetmap.org/api/0.6/user/details",
    method: "GET",
    oauth: {
        consumer_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Supply the consumer key, consumer secret, access token and access secret for every request to the API.
        consumer_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        token: req.session.access_token,
        token_secret: req.session.access_token_secret
    },
    headers: {
        "content-type": "text/xml" // Don't forget to set the content type as XML.
    }
}, (err, rs, body) => {
    // Do anything with the body.
});