Code Monkey home page Code Monkey logo

passport-twitter-oauth2's Introduction

Twitter OAuth 2.0 Strategy for Passport

@superfaceai/passport-twitter-oauth2

npm license TypeScript GitHub Discussions

Passport strategy for authenticating with Twitter using OAuth 2.0.

This module lets you authenticate using Twitter in your Node.js applications. By plugging into Passport, Twitter authentication can be integrated into any application or framework that supports Connect-style middleware, including Express.

Twitter announced OAuth 2.0 general availability on December 14 2021 and encourages developers to use Twitter API v2.0 with OAuth 2.0 authentication.

Twitter OAuth 2.0 implementation specifics:

  • PKCE is required
  • OAuth2 client credentials must be passed via Authorization header for confidential client types

Install

npm install @superfaceai/passport-twitter-oauth2

Usage

Note Check our blog for a complete tutorial with code explanation.

Create an Application

Before using @superfaceai/passport-twitter-oauth2, you must register a project and an application with Twitter by following these steps:

  1. go to https://developer.twitter.com/ and either sign up for a new account or sign in with existing one
  2. sign up for Essential access; you will need to verify a phone number for your Twitter account
  3. create a project and application (Essential account is limited to a single project and application)
  4. in application settings generate OAuth 2.0 Client ID and Client Secret; mind that you cannot view the secret again later, only regenerate it

Configure Strategy

Provide OAuth 2.0 Client ID and Client Secret (from previous step) to the strategy constructor. The strategy also requires a verify callback, which receives the access token and refresh token as arguments, as well as profile which contains the authenticated user's Twitter profile. The verify callback must call cb providing a user to complete authentication.

passport.use(
  new TwitterStrategy(
    {
      clientType: 'confidential', //depends on your Twitter app settings, valid values are `confidential` or `public`
      clientID: TWITTER_CLIENT_ID,
      clientSecret: TWITTER_CLIENT_SECRET,
      callbackURL: 'http://127.0.0.1:3000/auth/twitter/callback',
    },
    function (accessToken, refreshToken, profile, done) {
      User.findOrCreate({ twitterId: profile.id }, function (err, user) {
        return done(err, user);
      });
    }
  )
);

Authenticate Requests

Use passport.authenticate(), specifying the 'twitter' strategy, to authenticate requests.

Do not forget to configure scopes required by your application.

For example, you can use authenticate function as an Express route middleware:

app.get('/auth/twitter', passport.authenticate('twitter'));

app.get(
  '/auth/twitter/callback',
  passport.authenticate('twitter', {
    failureRedirect: '/login',
    scope: ['tweet.read', 'tweet.write', 'users.read'],
  }),
  function (req, res) {
    // Successful authentication, redirect home.
    res.redirect('/');
  }
);

Examples

Check the examples directory for minimal working projects:

Where It's Being Used

  • twitter-demo – Demo of social media profiles for Twitter with Superface OneSDK uses this strategy to generate access tokens.
  • social-media-demo – Demo application handling access to multiple social media sites, content publishing, reading timelines and more.

Related Projects

Development

When developing, start with cloning the repository using git clone https://github.com/superfaceai/passport-twitter-oauth2.git.

After cloning, install the dependencies with npm i.

Now the repository is ready for code changes.

The package.json also contains scripts (runnable by calling npm run <script-name>):

  • build - transpile TypeScript into JavaScript
  • format - check the code formatting
  • format:fix - fix the code formatting
  • lint - run linter
  • test - run tests

Contributing

Please open an issue first if you want to make larger changes

Feel free to contribute! Please follow the Contribution Guide.

Maintainers

License

@superfaceai/passport-twitter-oauth2 project is licensed under the MIT license.

© 2023 Superface s.r.o.

passport-twitter-oauth2's People

Contributors

adamjessop avatar dependabot[bot] avatar janhalama avatar jnv avatar leafaar avatar petrbela avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

passport-twitter-oauth2's Issues

Issue setting up Strategy [in TypeScript]

Hello, I am trying to setup an app to use this package but I am having issues setting the Strategy; specifically the following:

passport.use(
  new Strategy(
    {
      clientID: env.TWITTER_API_CLIENT_ID,
      clientSecret: env.TWITTER_API_CLIENT_SECRET,
      clientType: 'confidential',
      callbackURL: 'http://localhost:3000/auth/twitter/callback',
    },
    function (accessToken, refreshToken, profile, done) {
      return done(null, profile);
    }
  )
);

I have most commonly seen 2 errors between trying different things to resolve the issues:
1.

Property 'authenticate' is missing in type 'import(".../node_modules/@superfaceai/passport-twitter-oauth2/dist/strategy").Strategy' but required in type 'import(".../node_modules/@types/passport/index").Strategy'.
'Strategy' cannot be used as a value because it was exported using 'export type'.

I will add that I am using typescript (not sure if that should be causing these issues though) and I am working off the example code here

Thanks in advance for any help!!

TypeScript

Would it be possible to add TypeScript definitions for the package?

TokenError: Missing valid authorization header

I have search a lot a solution for my issue but i dont find it!

you are my last hope :) !

error i have when i connect with twitter i arrive to the twitter page and give the authorization on my twitter account after that i have this error:

TokenError: Missing valid authorization header
at OAuth2Strategy.parseErrorResponse (C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\passport-oauth2\lib\strategy.js:373:12)
at OAuth2Strategy._createOAuthError (C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\passport-oauth2\lib\strategy.js:420:16)
at C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\passport-oauth2\lib\strategy.js:177:45
at C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\oauth\lib\oauth2.js:191:18
at passBackControl (C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\oauth\lib\oauth2.js:132:9)
at IncomingMessage. (C:\Users\haatman\Desktop\dbq2formydev-main\dbq2formydev-main\bck\node_modules\oauth\lib\oauth2.js:157:7)
at IncomingMessage.emit (node:events:526:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

my code:

**middleware**
    require('dotenv').config();
const passport = require('passport');
const Strategy = require('@superfaceai/passport-twitter-oauth2').Strategy;
const TwitterUser = require('../models/TwitterUser');
const jwt = require('jsonwebtoken');

passport.serializeUser((user, done) => {
	if (user.provider === 'twitter') {
		//console.log('Twitter-userSerialize', user);
		//console.log('Twitter-userID', user.id);
		done(null, { type: 'twitterUser', idTwitter: user.id });
	} else {
		// L'utilisateur ne provient pas de Twitter, ne rien faire
		done();
	}
});

// Désérialise l'utilisateur à partir de la session
passport.deserializeUser(async (serializedUser, done) => {
	if (serializedUser.type === 'twitterUser') {
		try {
			let user = await TwitterUser.findById(serializedUser.idTwitter);
			// console.log('twitterUser', user)
			done(null, user);
		} catch (error) {
			done(error, null);
		}
	} else {
		done();
	}
});

// Use the Twitter OAuth2 strategy within Passport
passport.use(
	// <2> Strategy initialization
	new Strategy(
		{
			clientID: process.env.TWITTER_CLIENT_ID,
			clientSecret: process.env.TWITTER_CLIENT_ID_SECRET,
			clientType: 'confidential',
			callbackURL: process.env.CALLBACK_TWITTER,
		},
		// <3> Verify callback
		async (accessToken, refreshToken, profile, done) => {
			//console.log(profile);

			try {
				const { id, _json } = profile;
				const name = _json.name;
				const screen_name = _json.screen_name;
				const followers_count = _json.followers_count;
				const findUser = await TwitterUser.findOne({ twitterId: id });

				if (findUser) {
					console.log('access token', accessToken);
					console.log('tokenSecret', refreshToken);
					findUser.accessToken = jwt.sign(
						{ accessToken },
						process.env.JWT_TWITTER_CLIENT_TOKEN
					);
					findUser.refreshToken = jwt.sign(
						{ refreshToken },
						process.env.JWT_TWITTER_CLIENT_TOKEN_SECRET
					);

					await findUser.save();

					return done(null, findUser);
				} else {
					console.log('access token', accessToken);
					console.log('tokenSecret', refreshToken);
					//console.log('pofileTest',id,name, screen_name,followers_count)
					const newUser = await TwitterUser.create({
						twitterId: id,
						userName: name,
						screenName: screen_name,
						followersCount: followers_count,
						accessToken: jwt.sign(
							{ accessToken },
							process.env.JWT_TWITTER_CLIENT_TOKEN
						),
						refreshToken: jwt.sign(
							{ refreshToken },
							process.env.JWT_TWITTER_CLIENT_TOKEN_SECRET
						),
					});
					return done(null, newUser);
				}
			} catch (error) {
				console.error(error);
				return done(error, null);
			}
		}
	)
);

module.exports = passport;

my roads:

require('dotenv').config();
const express = require('express');
const passport = require('passport');
const isAuthenticated = require('../../middleware/authorized');

const router = express.Router();

router.get(
	'/twitter',
	passport.authenticate('twitter', {
		scope: [
			'tweet.read',
			'users.read',
			'like.read',
			'follows.read',
			'space.read',
			'list.read',
			'offline.access',
		],
	}),
	(req, res) => {
		res.status(200);
	}
);

router.get(
	'/twitter/redirect',
	passport.authenticate('twitter', {
		failureRedirect: 'http://localhost:3000/',
	}),
	(req, res) => {
		// Affectez les données de session à req.session.twitterSession
		res.redirect('http://localhost:3000/');
	}
);

router.get('/status', isAuthenticated, (req, res) => {
	//console.log(req);
	if (req.user) {
		res.status(200).send(req.user);
	} else {
		res.status(401).json({ message: 'Unauthorized' });
	}
});
module.exports = router;

express-session and save cookie into mongoose

// appTwitter.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const MongoStore = require('connect-mongo');
require('./middleware/twitter');

const twitterSession = express();

twitterSession.use(
	session({
		secret: process.env.SESSION_SECRET_TWITTER,
		resave: false,
		saveUninitialized: false,
		cookie: {
			maxAge: 6000 * 60 * 24 * 7,
		},
		store: MongoStore.create({
			mongoUrl:
				**********************************************************************************,
			collectionName: 'sessionTwitter',
		}),
		name: 'twitterConnect',
	})
);

twitterSession.use(passport.initialize());

twitterSession.use(passport.session());
// ... autres configurations spécifiques à Twitter

module.exports = twitterSession;

I hope someone can help me i ty by advance :)

If you need other information tell me.

Twitter displays authorization dialog every time

Every time I call my passport.authenticate("twitter",...) for the same user, Twitter shows me the standard App wants to access your Twitter account. page. I do see my app in the Connected apps setting with the scopes I requested but still, the authorization page is shown every time.

The authorization page is shown one time only when I use passport-google-oauth20 or passport-facebook. With every subsequent passport.authenticate(...) call it just calls the redirect/callback without showing anything to the user. I would expect the same behaviour for Twitter. Is it possible to achieve this behaviour?

Version: 1.2.2

My configuration:

import { Strategy as TwitterStrategy } from "@superfaceai/passport-twitter-oauth2";
....
  passport.use(new TwitterStrategy({
    clientID: TWITTER_CLIENT_ID,
    clientSecret: TWITTER_CLIENT_SECRET,
    callbackURL: "/auth/twitter/redirect",
    clientType: "confidential"
  }, async (accessToken, refreshToken, profile, done) => {
    console.log("> twitter profile: ", profile);
    ///.....
  }));
router.get("/twitter", passport.authenticate("twitter", { scope: ['tweet.read', 'users.read'] }));

router.get("/twitter/redirect", passport.authenticate("twitter"), (req, res) => {
  res.status(200).json({ success: true });
});

Btw, thanks for the amazing library!

Encountering a 401 Unauthorized error while trying to authenticate on Twitter.

Screenshot 2024-06-07 at 11 36 45 PM
`import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from '@superfaceai/passport-twitter-oauth2';
import { Config } from 'src/utils/config';

@Injectable()
export class TwitterStrategy extends PassportStrategy(
Strategy,
'twitter-strategy',
) {
constructor() {
super({
clientID: Config.TWITTER_CLIENT_ID,
clientSecret: Config.TWITTER_CLIENT_SECRET,
clientType: 'public',
callbackURL: ${Config.BACKEND_URL}/account-verification/twitter/callback,
scope: ['users.read', 'offline.access', 'tweet.read'],
passReqToCallback: true,
state: true,
});
}

async validate(
req: any,
accessToken: string,
refreshToken: string,
profile: any,
done: any,
) {
const { id, username } = profile;
const twitter: any = {};
twitter.twitterId = id;
twitter.username = username;
done(null, twitter);
}
async authenticate(req: any, options?: any) {
try {
return super.authenticate(req, options);
} catch (error) {
if (error.statusCode === 401) {
console.log('Unauthorized')
}
throw error;
}
}
}
`

I attempted different approaches to handle the 401 error, but none were successful. Could you guide me on how to effectively manage this issue in the provided code snippet?

Implicit scope is not used and isn't sufficient

In #11 a default scope of users.read was introduced.

However, when creating a minimum viable server for this strategy I noticed two issues with this implicit behavior:

  • Scope users.read is insufficient for accessing user's profile, the endpoint requires both users.read and tweet.read (probably to access the pinned tweet, regardless whether it is requested or not)
  • Probably more significant, the default scope isn't picked up during authenticate call. Debugging the issue, I found that the underlying OAuth2 Strategy reads the default scope from _scope if not passed in during the authenticate call:

https://github.com/jaredhanson/passport-oauth2/blob/5fcd4c5238a3785794c8c8d0b4a1ab94f1f67bc1/lib/strategy.js#L231

In retrospect, I think this functionality couldn't work. Which is weird, because the test seem to asses this functionality.

Here is the code I am using:

const express = require('express');
const passport = require('passport');
const { Strategy } = require('@superfaceai/passport-twitter-oauth2');
const session = require('express-session');
require('dotenv').config();

// <1> Serialization and deserialization
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(
  // <2> Strategy initialization
  new Strategy(
    {
      clientID: process.env.TWITTER_CLIENT_ID,
      clientSecret: process.env.TWITTER_CLIENT_SECRET,
      clientType: 'confidential',
      callbackURL: `${process.env.BASE_URL}/auth/twitter/callback`,
      skipUserProfile: false,
    },
    // <3> Success callback
    (accessToken, refreshToken, profile, done) => {
      console.log('Success!', { accessToken, refreshToken });
      return done(null, profile);
    }
  )
);

const app = express();

app.use(passport.initialize());
// <4> Session initialization
app.use(
  session({ secret: 'keyboard cat', resave: false, saveUninitialized: true })
);

// <5> Start authentication flow
app.get(
  '/auth/twitter',
  passport.authenticate('twitter', {
    // scope: ['tweet.read', 'users.read', 'offline.access'],
  })
);

// <6> Callback handler
app.get(
  '/auth/twitter/callback',
  passport.authenticate('twitter'),
  function (req, res) {
    const userData = JSON.stringify(req.user, undefined, 2);
    res.end(
      `<h1>Authentication succeeded</h1> User data: <pre>${userData}</pre>`
    );
  }
);

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

When running this and visiting http://localhost:3000/auth/twitter, I get redirected to Twitter without the scope URL parameter.

passReqToCallback doesn't work in typescript

StrategyOptionWithRequest cannot be used with TwitterStrategy

image

Same when using options as an object straight into TwitterStrategy, and the verify function has the same problem, cannot get the types for passReqToCallback

"Unable to verify authorization request state." Error

Hello guys,

I am currently implementing Passport Twitter Auth in Nestjs using this library but I came across an error I can not solve:
"Unable to verify authorization request state." I have read comments about this issue online but none of them work for me.
I am using this on the localhost:3000

my express-session config:

  app.use(
    session({
      store: redisStore,
      secret: 'my-secret',
      resave: false,
      saveUninitialized: true,
      cookie: { secure: false, sameSite: false },
      // cookie: { secure: false, sameSite: "lax" },
    }),
  );

any idea what could go wrong here?

adding state within passport authenticate causes a failure

Hey there, I have returned once more,
I am trying to pass additional parameters via my query to the callback function however when I try adding the state
const authenticator = passport.authenticate('twitter', { scope: ['tweet.read', 'users.read', 'follows.read'], state});
authenticator(req, res, next);

the whole auth fails, any idea how I can resolve this?
Note: i know that twitter uses it's own state param, is there way i can add mine on top of it or add a different one

error with absence of oauth:twitter key

can you say what is a reason for error with absent key oauth:twitter on callback?
debug shows error in if
node_modules/passport-oauth2/lib/state/pkcesession.js
line 67
var key = this._key;
if (!req.session[key]) {
return callback(null, false, { message: 'Unable to verify authorization request state.' });
}

InternalOAuthError: Failed to obtain access token

InternalOAuthError: Failed to obtain access token
at OAuth2Strategy._createOAuthError (/Users/zht/Desktop/TON/t404/server/node_modules/.pnpm/[email protected]/node_modules/passport-oauth2/lib/strategy.js:423:17)
at /Users/zht/Desktop/TON/t404/server/node_modules/.pnpm/[email protected]/node_modules/passport-oauth2/lib/strategy.js:177:45
at /Users/zht/Desktop/TON/t404/server/node_modules/.pnpm/[email protected]/node_modules/oauth/lib/oauth2.js:196:18
at ClientRequest. (/Users/zht/Desktop/TON/t404/server/node_modules/.pnpm/[email protected]/node_modules/oauth/lib/oauth2.js:166:7)
at ClientRequest.emit (node:events:519:28)
at TLSSocket.socketErrorListener (node:_http_client:500:9)
at TLSSocket.emit (node:events:519:28)
at emitErrorNT (node:internal/streams/destroy:169:8)
at emitErrorCloseNT (node:internal/streams/destroy:128:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Users which are not logged in before authorization

Hello,
Not sure if this is an issue with this library or i am just not understanding the twitter auth flow.
if a user who has not been logged in initially tries to authorize it asks them to login and with that it does not hit the callback again,
how do i resolve this issue?

NestJs Integration - InternalOAuthError

Hi,

I am struggling to integrate this passport strategy with NestJs. I have tried a number of different ways, from using the official AuthGuard and strategy class to calling passport.use / passport.authenticate directly with the same strategy instance.

Here is my strategy class:

import { PassportStrategy } from '@nestjs/passport';
import * as TwitterStrategy from '@superfaceai/passport-twitter-oauth2';
...

@Injectable()
export class TenantTwitterAuthStrategy extends PassportStrategy(TwitterStrategy, 'twitter') {
    private readonly configService: ConfigService;

    constructor(config: ConfigService) {
        super({
            clientID: config.get('TWITTER_CLIENT_ID'),
            clientSecret: config.get('TWITTER_CLIENT_SECRET'),
            callbackURL: `${config.get('HOST')}/auth/tenant/twitter/redirect`,
            clientType: 'private',
            scope: ['tweet.read', 'offline.access'],
            passReqToCallback: true,
        });
        this.configService = config;
    }

    public validate(req: IAuthedRequest, accessToken: string, refreshToken: string, profile: TwitterStrategy.Profile) {
    
        ....
     }

I have attempted to debug, and I can see the the userProfile function is getting what looks like a valid accessToken, and the url object is:

{
  href: 'https://api.twitter.com/2/users/me?user.fields=profile_image_url,url',
  origin: 'https://api.twitter.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'api.twitter.com',
  hostname: 'api.twitter.com',
  port: '',
  pathname: '/2/users/me',
  search: '?user.fields=profile_image_url,url',
  searchParams: URLSearchParams { 'user.fields' => 'profile_image_url,url' },
  hash: ''
}

which looks correct. However it's throwing an InternalOAuthError: Failed to fetch user profile.

Which is a result of a 403 Forbidden response coming back from the profile call.

Has anyone managed to sucessfully integrate this with NestJs. I haven't had issues with other providers or indeed the original passport-twitter library, however I am wanting to use the v2 API.

Refresh token is missing

HI 👋🏽

thanks for your library. I have an issue that I don't get a refresh token. I set the scope to "offline.access" and I get the refresh token when I make the call manually with a fetch. Not sure what the issue is. Here is my code:

Strategy

passport.use(
    new TwitterStrategy(
      {
        clientID: clientId,
        clientSecret:clientSecret,
        callbackURL: callbackUrl,
        scope: ["follows.read", "tweet.read", "users.read", "offline.access"],
        clientType: "private",
      },
      async (accessToken, refreshToken, profile, done) => {
        return done(null, profile, accessToken, refreshToken);
      }
    )
  );

Init Auth

  router
    .route("/twitter")
    .get(
      passport.authenticate("twitter", {
        scope: [
          "follows.read",
          "tweet.read",
          "users.read",
          "offline.access"
        ],
        callbackURL: callbackUrl,
      })
    );

Callback

 router.route("/callback/twitter").get((req, res, next) => {
    passport.authenticate(
      "twitter",
      async (err, profile, accessToken, refreshToken) => {
        try {
          console.log("Access token: ", accessToken);
          console.log("refreshToken: ", refreshToken);
    
          res.redirect("/");
        } catch (error) {
          console.log("ee", error);
          res.redirect("/");
        }
      }
    )(req, res, next);
  });

How can we persist session? also Profile is null

Quick question: Please look at ===>
const twitterCallback = (accessToken, refreshToken, profile, done) => {
console.log("twitter profile", profile); ===> Profile does not print anything here
done(null, profile);
};

Also how can we persist session with express "cookie-session" similar to passport-twitter so we can have "req.user" in the session object?
router.get("/success", (req, res) => {
console.log(req.user); ===> req use is null

res.redirect(payload);
});

Why OAuth 2.0 protocol requires a session support?

When I provide an {session: false} option to passport.authenticate() method, it gives the error below:

Error: OAuth 2.0 authentication requires session support when using state. Did you forget to use express-session middleware?

As I know Twitter started to fully support OAuth 2.0 protocol relatively recently, so now we are able to use this auth protocol on scheme like application-user authentication (OAuth 2.0 Authorization Code Flow with PKCE), and not only for application-only authentication (App only). Thus, this new feature enables the use case where we can handle an auth flow on our own, e.g. using it without session at all. That's why, passport provides {session: false} option to disable keeping tokens in a session when needed to query the API on behalf of users without using libraries like express-session, and passport already supports this working style for Google, Facebook and etc.

To better understand the issue, you can refer (at that time Twitter didn't support OAUTH 2.0 with PKCE, but anyway the discussion makes sense so far):
https://stackoverflow.com/questions/44071555/why-passport-twitter-requires-session-support

Could you please enable the option {session: false} passed into passport.authenticate()? And, if this library already supports this behavior, could you please give me a hint to fix this issue? Thanks.

Something went wrong

Hi, is this still maintained etc?

I am getting a screen stating that something went wrong and:
"You weren’t able to give access to the App. Go back and try logging in again."

I have also tried your sample twitter-demo app and had the same result. Is there something that needs updating here?

How to retrieve the email address?

I am tryuing to receive the email address from the profile in the passportTwitterV2Strategy but I can't find the includeEmailAddress param anywhere.

Can you please help?

how to disable pkce flow?

I try to disable pkce usage by setting option pkce: false, but when see strategy, pkce still is ictive
my code:

const twitterStrategy =     // <2> Strategy initialization
    new Strategy(
        {
            clientID: process.env.TWITTER_CLIENT_ID,
            clientSecret: process.env.TWITTER_CLIENT_SECRET,
            clientType: 'public',
            callbackURL,
            pkce: false,
        },
        // <3> Verify callback
        (accessToken, refreshToken, profile, done) => {
            console.log('Success!', { accessToken, refreshToken });
            return done(null, profile);
        }
    )
console.dir(twitterStrategy);

but twitterStrategy is, and it seems that pkce is on

Strategy {
  name: 'twitter',
  _verify: [Function (anonymous)],
  _oauth2: {
    _clientId: 'Z3lZMlFzMHZocnIwbmtZc001Zmo6MTpjaQ',
    _clientSecret: '9E2rUQlpQKuVwKAWpnLcJb53IxjSfhQiZA9sHYwfmB4yOFya1u',
    _baseSite: '',
    _authorizeUrl: 'https://twitter.com/i/oauth2/authorize',
    _accessTokenUrl: 'https://api.twitter.com/2/oauth2/token',
    _accessTokenName: 'access_token',
    _authMethod: 'Bearer',
    _customHeaders: {
      Authorization: 'Basic WjNsWk1sRnpNSFpvY25Jd2JtdFpjMDAxWm1vNk1UcGphUTo5RTJyVVFscFFLdVZ3S0FXcG5MY0piNTNJeGpTZmhRaVpBOXNIWXdmbUI0eU9GeWExdQ=='
    },
    _useAuthorizationHeaderForGET: false,
    _agent: undefined
  },
  _callbackURL: 'http://127.0.0.1:3000/social/callback/twitter',
  _scope: undefined,
  _scopeSeparator: ' ',
  _pkceMethod: 'S256',
  _key: 'oauth:twitter',
  _stateStore: PKCESessionStore { _key: 'oauth:twitter' },
  _trustProxy: undefined,
  _passReqToCallback: undefined,
  _skipUserProfile: false,
  _userProfileURL: 'https://api.twitter.com/2/users/me?user.fields=profile_image_url,url'
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.