Skip to content

Commit

Permalink
make some improvements to oauth article re: #40
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Jan 19, 2020
1 parent dfe0da1 commit 47b6fe1
Showing 1 changed file with 19 additions and 12 deletions.
31 changes: 19 additions & 12 deletions lib/posts/20200114_oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ The auth server needs 4 endpoints:
3. A route to exchange an auth code for an access token.
4. A "secure" endpoint that only responds if it is given a valid access token via the [`Authorization` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization).

Since the auth server will run on a different domain than the client app, it also needs [CORS](https://masteringjs.io/tutorials/fundamentals/cors) in order to avoid the browser throwing errors about cross-origin requests.
Since the auth server will run on a different domain than the client app, it also needs [CORS](https://masteringjs.io/tutorials/fundamentals/cors) for the
access token and secure endpoints in order to avoid the browser throwing errors about cross-origin requests. However, it is important to protect the endpoint
for getting an auth code secure from cross-origin requests because of
[CSRF attacks](https://www.twilio.com/blog/2018/01/protect-your-node-js-app-from-cross-site-request-forgery.html).

The flow starts when the user opens the OAuth dialog. In this example,
the authorization server has a static `oauth-dialog.html` file that
Expand All @@ -121,13 +124,10 @@ for generating an auth code and redirecting to the client app.
<html>
<body>
<div>Authorize OAuth Test App?</div>
<button>OK</button>

<script type="text/javascript">
document.querySelector('button').addEventListener('click', () => {
window.location.href = '/code';
});
</script>
<form action="/code" method="POST">
<button type="submit">OK</button>
</form>
</body>
</html>
```
Expand All @@ -150,12 +150,11 @@ async function run() {
const authCodes = new Set();
const accessTokens = new Set();

app.use(cors());
app.use(express.json());

// Generate an auth code and redirect to your app client's
// domain with the auth code
app.get('/code', (req, res) => {
app.post('/code', (req, res) => {
// Generate a string of 10 random digits
const authCode = new Array(10).fill(null).map(() => Math.floor(Math.random() * 10)).join('');

Expand All @@ -166,8 +165,11 @@ async function run() {
res.redirect(`http://localhost:3000/oauth-callback.html?code=${authCode}`);
});

app.options('/token', cors(), (req, res) => res.end());
app.options('/secure', cors(), (req, res) => res.end());

// Verify an auth code and exchange it for an access token
app.post('/token', (req, res) => {
app.post('/token', cors(), (req, res) => {
if (authCodes.has(req.body.code)) {
// Generate a string of 50 random digits
const token = new Array(50).fill(null).map(() => Math.floor(Math.random() * 10)).join('');
Expand All @@ -177,11 +179,11 @@ async function run() {
res.json({ 'access_token': token, 'expires_in': 60 * 60 * 24 });
} else {
res.status(400).json({ message: 'Invalid auth token' });
}
}
});

// Endpoint secured by auth token
app.get('/secure', (req, res) => {
app.get('/secure', cors(), (req, res) => {
const authorization = req.get('authorization');
if (!accessTokens.has(authorization)) {
return res.status(403).json({ message: 'Unauthorized' });
Expand All @@ -198,6 +200,11 @@ async function run() {
}
```

Note that the `/code` endpoint, as written, is vulnerable to [cross-site request forgery attacks](https://www.twilio.com/blog/2018/01/protect-your-node-js-app-from-cross-site-request-forgery.html). A malicious
website could POST a form to the `/code` endpoint and that would trigger the
OAuth flow without the user's knowledge. You can use a module like
[csurf](https://github.com/expressjs/csurf) to generate CSRF tokens.

Moving On
---------

Expand Down

0 comments on commit 47b6fe1

Please sign in to comment.