John Lippson
John Lippson

Reputation: 1329

Correct way to implement Github OAuth in client-side application?

I'm adding OAuth into my github clientside application. I have the final auth token being returned successfully, but I feel like I hacked my workflow.

Current Architecture Flow:

1) User clicks href link from component to hit the initial OAUTH route

2) Retrieve token from Github for user identity

3) Github redirects to my server route and my server route sends an additional POST to the /access_token request page with the client_secret, id and code from the above step.

4) Finally I redirect from the above route back to my UI and set a URL parameter in the process

5) In the componentDidMount I strip the final auth token from the window.url and set it in my state

Note: I plan on storing the token in Redux later, but this is the base level as to what I'm doing.

Actual Code

Server

app.get("/login", async (req, res) => {
  // Get the identity token from GitHub origin
  return await axios
    .post("https://github.com/login/oauth/access_token", {
      code: req.query.code,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET
    })
    .then(async resp => {
      // Little hack to parse out the query params into an object 
      let data = await url.parse("http://parse.com?" + resp.data, {
        parseQueryString: true
      }).query;

      res.redirect(
        url.format({
          pathname: Environment.getUrl(),
          query: {
            token: data.access_token
          }
        })
      );
    });
});

UI Authentication Component

export default class GithubAuthentication extends React.Component {
  state = {
    authToken: "DATA"
  };

  componentDidMount() {
    let currUrl = window.location.href;
    this.setState({ authToken: currUrl.split("token=")[1] });
  }

  render() {
    return (
      <React.Fragment>
        <a href="https://github.com/login/oauth/authorize?client_id=b5cd37110eb31620aad7">
          {this.state.authToken ? "Logout" : "Login With Github"}
        </a>
        <span>{this.state.authToken}</span>
      </React.Fragment>
    );
  }
}

Questions

1) The one thing I wasn't able to figure out was to make the href link a controlled component and actually hit the auth URL with something like SuperAgent or Axios. Instead, I'm forced to use this href link, not sure why.

2) Is this actually a sensible flow for getting the final auth token?

Upvotes: 2

Views: 1632

Answers (2)

toshi
toshi

Reputation: 2814

Regarding question 2, from a security standpoint, it is better to keep access token on server-side and never send the token to client-side.

I couldn't find good written resources, so I'd like to share this video which sums up how to deal with access token clearly.

https://www.youtube.com/watch?v=CHzERullHe8&list=PL78z2Z3ZApYcKb-GDQt6ikdN2EDqmKJrT&index=12&t=419s

Take away from the video

  • We still don't have a good way to securely store the token on the browser
  • By storing the access token on the server-side and using session cookie, you can minimize the risk of access token being compromised.

To actually implement this flow, you can use cookie-session to generate session. You can also use github-passport to simplify the implementation.

https://github.com/expressjs/cookie-session https://github.com/jaredhanson/passport-github

Upvotes: 1

KamyarN
KamyarN

Reputation: 145

1) I think you should reorganize your app so that you can use a component instead of an href link. You would know whether you're authenticated or not based on the value on the state property. This value can be passed as prop to your component which is where you would put the logic of authenticated ? "Logout" : "Login" or anything else.

2) the flow is OK but you have to make sure you do server side validation of the token since it's easy to just flip the switch on the UI and the pretend you're authenticated very easily.

Upvotes: 0

Related Questions