iOS & node.js: how to verify passed access token?

In production for google you can use:

https://www.npmjs.com/package/google-auth-library

const ticket = client.verifyIdToken({
    idToken: ctx.request.body.idToken,
    audience: process.env.GOOGLE_CLIENTID
})

For google in production, install google-auth-library (npm install google-auth-library --save) and use the following:

const { OAuth2Client } = require('google-auth-library');
const client = new OAuth2Client(GOOGLE_CLIENT_ID); // Replace by your client ID

async function verifyGoogleToken(token) {
  const ticket = await client.verifyIdToken({
    idToken: token,
    audience: GOOGLE_CLIENT_ID  // Replace by your client ID 
  });
  const payload = ticket.getPayload();
  return payload;
}

router.post("/auth/google", (req, res, next) => {
  verifyGoogleToken(req.body.idToken).then(user => {
    console.log(user); // Token is valid, do whatever you want with the user 
  })
  .catch(console.error); // Token invalid
});

More info on Authenticate google token with a backend server, examples for node.js, java, python and php can be found.

For Facebook, do an https request like:

const https = require('https');

router.post("/auth/facebook", (req, res, next) => {

  const options = {
    hostname: 'graph.facebook.com',
    port: 443,
    path: '/me?access_token=' + req.body.authToken,
    method: 'GET'
  }

  const request = https.get(options, response => {
    response.on('data', function (user) {
      user = JSON.parse(user.toString());
      console.log(user);
    });
  })

  request.on('error', (message) => {
    console.error(message);
  });

  request.end();
})

To the best of my knowledge (and as far as I can tell from reading the specifications) the OAuth and OAuth 2 specs do not specify a single endpoint for access token validation. That means you will need custom code for each of the providers to validate an access token only.

I looked up what to do for the endpoints you specified:

Facebook

It seems others have used the graph API's 'me' endpoint for Facebook to check if the token is valid. Basically, request:

https://graph.facebook.com/me?access_token={accessToken}

Google

Google have a dedicated debugging endpoint for getting access token information, with nice documentation, too. Basically, request:

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={accessToken}

However, they recommend that you don't do this for production:

The tokeninfo endpoint is useful for debugging but for production purposes, retrieve Google's public keys from the keys endpoint and perform the validation locally. You should retrieve the keys URI from the Discovery document using the jwks_uri metadata value. Requests to the debugging endpoint may be throttled or otherwise subject to intermittent errors.

Since Google changes its public keys only infrequently, you can cache them using the cache directives of the HTTP response and, in the vast majority of cases, perform local validation much more efficiently than by using the tokeninfo endpoint. This validation requires retrieving and parsing certificates, and making the appropriate cryptographic calls to check the signature. Fortunately, there are well-debugged libraries available in a wide variety of languages to accomplish this (see jwt.io).

Twitter

Twitter doesn't seem to have a really obvious way to do this. I would suspect that because the account settings data is pretty static, that might be the best way of verifying (fetching tweets would presumably have a higher latency?), so you can request (with the appropriate OAuth signature etc.):

https://api.twitter.com/1.1/account/settings.json

Note that this API is rate-limited to 15 times per window.

All in all this seems trickier than it would first appear. It might be a better idea to implement some kind of session/auth support on the server. Basically, you could verify the external OAuth token you get once, and then assign the user some session token of your own with which you authenticate with the user ID (email, FB id, whatever) on your own server, rather than continuing to make requests to the OAuth providers for every request you get yourself.

Hope that helps!