Skip to main content
  1. About
  2. For Teams
Asked
Viewed 816 times
2

I need to implement a github authorization and later send received data (JSON) to the client.

I found this tutorial http://shiya.io/how-to-do-3-legged-oauth-with-github-a-general-guide-by-example-with-node-js/

In that tutorial developer shows us this way: "/" -> "/login" -> "/redirect" -> "/user"(data here)

But i need: "/" -> "/login" -> "/redirect" -> "/"(data here)

Because the client is supposed to uses simple SPA(react).

What i have now:


    require('dotenv').config();
    const express = require('express');
    const app = express();
    const session = require('express-session');
    const request = require('request');
    const qs = require('querystring');
    const url = require('url');
    const randomString = require('randomstring');
    const csrfString = randomString.generate();

    const port = process.env.PORT || 8080;
    const redirect_uri = process.env.HOST + '/redirect';

    app.use(express.static('views'));

    app.use(
      session({
        secret: randomString.generate(),
        cookie: { maxAge: 60000 },
        resave: false,
        saveUninitialized: false
      })
    );

    app.get('/', (req, res, next) => {
      res.sendFile(__dirname + '/index.html');
      if (req.session.access_token) {
        request.get(
          {
            url: 'https://api.github.com/user',
            headers: {
              Authorization: 'token ' + req.session.access_token,
              'User-Agent': 'Login-App'
            }
          },
          (error, response, body) => {
            res.send(body);
          }
        );
      }
    });

    app.listen(port, () => {
      console.log('Server listening at port ' + port);
    });

    app.get('/login', (req, res, next) => {
    req.session.csrf_string = randomString.generate();
    const githubAuthUrl =
      'https://github.com/login/oauth/authorize?' +
      qs.stringify({
        client_id: process.env.CLIENT_ID,
        redirect_uri: redirect_uri,
        state: req.session.csrf_string,
        scope: 'user:email'
      });
    res.redirect(githubAuthUrl);
    });

    app.all('/redirect', (req, res) => {
      console.log('Request sent by GitHub: ');
      console.log(req.query);

      const code = req.query.code;
      const returnedState = req.query.state;

      if (req.session.csrf_string === returnedState) {
        request.post(
          {
            url:
              'https://github.com/login/oauth/access_token?' +
              qs.stringify({
                client_id: process.env.CLIENT_ID,
                client_secret: process.env.CLIENT_SECRET,
                code: code,
                redirect_uri: redirect_uri,
                state: req.session.csrf_string
              })
          },
          (error, response, body) => {
            console.log('Your Access Token: ');
            console.log(qs.parse(body));
            req.session.access_token = qs.parse(body).access_token;

            res.redirect('/');
          }
        );
      } else {
        res.redirect('/');
      }
      console.log(redirect_uri);
    });

In this moment res.send(body); throws an error


    app.get('/', (req, res, next) => {
      res.sendFile(__dirname + '/index.html');
      if (req.session.access_token) {
        request.get(
          {
            url: 'https://api.github.com/user',
            headers: {
              Authorization: 'token ' + req.session.access_token,
              'User-Agent': 'Login-App'
            }
          },
          (error, response, body) => {
            res.send(body);
          }
        );
      }
    });

Error:

    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

It happens because I trying to set data for rendering after rendering.

So, my question:

How i can to send data to a client and how get it on client side?

1 Answer 1

4

HTTP uses a cycle that requires one response per request. When the client sends a request the server should send only one response back to client.

Your are sending two response res.sendFile() & res.send() for one request, So your code need to be changed as follows,

app.get('/', (req, res, next) => {
    if (req.session.access_token) {
        request.get({
            url: 'https://api.github.com/user',
            headers: { Authorization: 'token ' + req.session.access_token, 'User-Agent': 'Login-App' }
        }, (error, response, body) => { res.send(body); }
        );
    } else {
        res.sendFile(__dirname + '/index.html');
    }
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.