Skip to content
Advertisement

How to Login to MediaWiki (Wikipedia) API in Node.js

I’m trying the Wikipedia client login flow depicted in the API:Login docs, but something wrong happens:

1) I correctly get a token raised with the HTTP GET https://en.wikipedia.org/w/api.php?action=query&meta=tokens&type=login&format=json

and I get a valid logintoken string.

2.1) I then try the clientlogin like:

HTTP POST /w/api.php?action=clientlogin&format=json&lgname=xxxx&lgtoken=xxxx%2B%5C

and the POST BODY was

{
    "lgpassword" : "xxxxx",
    "lgtoken" : "xxxxx"
}

But I get an error:

{
  "error": {
    "code": "notoken",
    "info": "The "token" parameter must be set."
 },
  "servedby": "mw1228"
}

If I try to change lgtoken to token I get the same result.

2.2) I have then tried the old method i.e. action=login and passing the body, but it does not work, since it gives me back another login token: HTTP POST https://en.wikipedia.org/w/api.php?action=login&format=json&lgname=xxxx

and the same POST BODY

I then get

{
  "warnings": {}
  },
  "login": {
    "result": "NeedToken",
    "token": "xxxxx+\"

}

where the docs here states that

NeedToken if the lgtoken parameter was not provided or no session was active (e.g. your cookie handling is broken).

but I have passed the lgtoken in the json body as showed. I’m using Node.js and the built-in http module, that is supposed to pass and keep session Cookies in the right way (with other api it works ok).

I have found a similar issue on a the LrMediaWiki client here.

[UPDATE] This is my current implementation:

  Wikipedia.prototype.loginUser = function (username, password) {
      var self = this;
      return new Promise((resolve, reject) => {

        var cookies = self.cookies({});
        var headers = {
          'Cookie': cookies.join(';'),
          'Accept': '*/*',
          'User-Agent': self.browser.userAgent()
        };
        // fetch login token
        self.api.RequestGetP('/w/api.php', headers, {
          action: 'query',
          meta: 'tokens',
          type: 'login',
          format: 'json'
        })
          .then(response => { // success
            if (response.query && response.query.tokens && response.query.tokens['logintoken']) {
              self.login.logintoken = response.query.tokens['logintoken'];
              self.logger.info("Wikipedia.login token:%s", self.login);
              return self.api.RequestPostP('/w/api.php', headers, {
                action: 'login',
                format: 'json',
                lgname: username
              },
                {
                  lgpassword: password,
                  lgtoken: self.login.logintoken
                });
            } else {
              var error = new Error('no logintoken');
              return reject(error);
            }
          })
          .then(response => { // success
            return resolve(response);
          })
          .catch(error => { // error
            self.logger.error("Wikipedia.login error%sn%@", error.message, error.stack);
            return reject(error);
          });
      });
    }//loginUser

where this.api is a simple wrapper of the Node.js http, the source code is available here and the api signatures are like:

Promise:API.RequestGetP(url,headers,querystring)
Promise:API.RequestPostP(url,headers,querystring,body)

Advertisement

Answer

I think from what you are saying you have lgtoken and lgname in the URL you are using, and then lgpassword and lgtoken (again!) in a JSON-encoded POST body.

This is not how the Mediawiki API works.

You submit it all as POST parameters. JSON is never involved, except when you ask for the result to come back in that format. I can’t help you fix your code as you don’t provide it, but that’s what you need to do. (If you edit your question with your code, I’ll do my best to help you.)

After seeing your code, I’ll presume (without knowing the detail of your code) that you want something like this:

          return self.api.RequestPostP('/w/api.php', headers, {
            action: 'login',
            format: 'json',
            lgname: username,
            lgpassword: password,
            lgtoken: self.login.logintoken
          });
Advertisement