Skip to content

Commit

Permalink
docs: example for passing state during twitter auth flow (#49)
Browse files Browse the repository at this point in the history
* state usage

* apply review comments
  • Loading branch information
MuizNadeem authored Feb 2, 2025
1 parent 885ed09 commit 43316fe
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/state-usage/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BASE_URL=http://localhost:3000
TWITTER_CLIENT_ID="OAuth 2.0 Client ID from Twitter Developer portal"
TWITTER_CLIENT_SECRET="OAuth 2.0 Client Secret from Twitter Developer portal"
29 changes: 29 additions & 0 deletions examples/state-usage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Plain JavaScript example for passing state during authentication flow with Passport Twitter OAuth 2.0 Strategy

This is an example of passing state during the authentication flow with Passport and `@superfaceai/passport-twitter-oauth2` packages on Express server. After a successful login, the application shows user profile information, the state that was passed during the authentication request and logs the access token to a console.

Check [`@superfaceai/passport-twitter-oauth2`](https://github.com/superfaceai/passport-twitter-oauth2) for more info about the package and [step-by-step tutorial](https://superface.ai/blog/twitter-oauth2-passport) on setting up the Twitter application.

## Setup

1. Install dependencies
```shell
npm i
```
1. Copy `.env.example` to `.env`
```shell
cp .env.example .env
```
1. Paste your Client ID and Client Secret from Twitter developer portal to `.env` file

## Usage

1. Start the server with
```shell
npm start
```
1. Visit `http://localhost:3000/auth/twitter?state=my-very-long-state-12234567890`

## Troubleshooting

If you run into any issues with the example, please don't hesitate to [open an issue](https://github.com/superfaceai/passport-twitter-oauth2/issues/new).
21 changes: 21 additions & 0 deletions examples/state-usage/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "state-usage",
"version": "1.0.0",
"description": "Plain JavaScript example for passing state during the authentication flow with Passport Twitter OAuth 2.0 Strategy",
"main": "server.js",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@superfaceai/passport-twitter-oauth2": "file:../..",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-session": "^1.17.3",
"passport": "^0.6.0"
}
}
76 changes: 76 additions & 0 deletions examples/state-usage/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const express = require('express');
const passport = require('passport');
const { Strategy } = require('@superfaceai/passport-twitter-oauth2');
const session = require('express-session');
require('dotenv').config();

passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});

// Use the Twitter OAuth2 strategy within Passport
passport.use(
new Strategy(
{
clientID: process.env.TWITTER_CLIENT_ID,
clientSecret: process.env.TWITTER_CLIENT_SECRET,
clientType: 'confidential',
callbackURL: `${process.env.BASE_URL}/auth/twitter/callback`,
},
(accessToken, refreshToken, profile, done) => {
console.log('Success!', { accessToken, refreshToken });
return done(null, profile);
}
)
);

const app = express();

app.use(passport.initialize());
app.use(
session({ secret: 'keyboard cat', resave: false, saveUninitialized: true })
);

app.get(
'/auth/twitter',
(req, res, next) => {
const stateObject = {
key: req.query.state
};

passport.authenticate('twitter', {
scope: ['tweet.read', 'users.read', 'offline.access'],
state: stateObject // Passing the state as an object is required by the Passport strategy
})(req, res, next);
}
);


app.get(
'/auth/twitter/callback',
passport.authenticate('twitter'),
function (req, res) {
// Regenerate the session to prevent session fixation attacks
req.session.regenerate(function (err) {
if (err) {
return res.status(500).json({ error: 'Failed to regenerate session' });
}

const state = JSON.stringify(req.session.req.authInfo.state, undefined, 2);
const userData = JSON.stringify(req.user, undefined, 2);
res.end(
`<h1>Authentication succeeded</h1> User data: <pre>${userData}</pre>
State:
<pre>${state}</pre>
`
);
});
}
);

app.listen(3000, () => {
console.log(`Listening on ${process.env.BASE_URL}`);
});

0 comments on commit 43316fe

Please sign in to comment.