Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is Twitter provider working? #53

Open
saneef opened this issue Oct 20, 2021 · 8 comments
Open

Is Twitter provider working? #53

saneef opened this issue Oct 20, 2021 · 8 comments

Comments

@saneef
Copy link

saneef commented Oct 20, 2021

Tried with Twitter, and it doesn't seems like working?

It gets stuck at a Twitter Error page at https://api.twitter.com/oauth/authorize?oauth_token=undefined.

@saneef
Copy link
Author

saneef commented Oct 20, 2021

I hadn't enabled Enable 3-legged OAuth on Twitter 🤦‍♂️

Sorry.

@saneef saneef closed this as completed Oct 20, 2021
@saneef
Copy link
Author

saneef commented Oct 21, 2021

Even after enabling 3-legged OAuth on Twitter, I'm facing this issue? Any clues?

@saneef saneef reopened this Oct 21, 2021
@angezanetti
Copy link

I have the same issue - with OAuth v1 and v2.

Did you managed to make it work?

@mitjakukovec
Copy link

mitjakukovec commented Mar 9, 2022

I just can't find where I can select Enable 3-legged OAuth. I am also not absolutely sure if I need to configure Twitter provider with API secret and key or with OAUTH client id and secret?

        new TwitterAuthProvider({
            apiKey: import.meta.env.VITE_TWITTER_API_KEY,
            apiSecret: import.meta.env.VITE_TWITTER_API_SECRET,
            profile(profile) {
                return { ...profile, provider: 'twitter' };
            },
        })

or

        new TwitterAuthProvider({
            apiKey: import.meta.env.VITE_TWITTER_OAUTH_CLIENT_ID,
            apiSecret: import.meta.env.VITE_TWITTER_OAUTH_CLIENT_SECRET,
            profile(profile) {
                return { ...profile, provider: 'twitter' };
            },
        })

There is API key/secret, Access token/secret and Oauth client id/secret.
image
So which one and how to use?

@nk113
Copy link

nk113 commented Apr 19, 2022

Would be better to write own twitter provider... I could have got this to work using twitter-api-v2 like below:

export const auth: SvelteKitAuth = new SvelteKitAuth({
  ...
  providers: [
    ...
    new class extends TwitterAuthProvider {
      constructor() {
        super({
          apiKey: process.env.AUTH_TWITTER_API_KEY,
          apiSecret: process.env.AUTH_TWITTER_API_SECRET,
          profile: (profile) => {
            return { ...profile, provider: 'twitter' };
          },
        })
      }
      getRequestToken = async (auth, host): Promise<any> => {
        const { url, ...oauthResult } = await (new TwitterApi({
          appKey: this.config.apiKey,
          appSecret: this.config.apiSecret
        })).readOnly.generateAuthLink(
          encodeURIComponent(this.getCallbackUri()), { authAccessType: 'read' }
        );
        return {
          oauthToken: oauthResult.oauth_token,
          oauthTokenSecret: oauthResult.oauth_token_secret,
          oauthCallbackConfirmed: oauthResult.oauth_callback_confirmed
        };
      }
      getTokens = async (oauthToken: string, oauthVerifier: string): Promise<any> => {
        const endpoint = 'https://api.twitter.com/oauth/access_token';

        const data = {
          oauth_consumer_key: this.config.apiKey,
          oauth_token: oauthToken,
          oauth_verifier: oauthVerifier,
        };

        const response: any = await fetch(`${endpoint}?${new URLSearchParams(data)}`, { method: 'POST' });
        // This endpoint returns query string like key-value pairs
        // https://developer.twitter.com/en/docs/authentication/api-reference/access_token
        return Object.fromEntries([...(new URLSearchParams(await response.text()))]);
      }
      getUserProfile = async ({ oauth_token, oauth_token_secret, ...account }: any) => {
        let user: any = {};
        try {
          // Need to apply for elevated access - not tested yet
          user = await (new TwitterApi({
            appKey: this.config.apiKey,
            appSecret: this.config.apiSecret,
            accessToken: oauth_token,
            accessSecret: oauth_token_secret,
          })).readOnly.currentUser();
        } catch (e) {
          // 403
        }
        return { ...user, ...account };
      }
      getCallbackUri(): string {
        return `${settings.AUTH_CALLBACK_URI_PREFIX}twitter`;
      }
    },
    ...

@xpluscal
Copy link

xpluscal commented Jun 3, 2022

Would be better to write own twitter provider... I could have got this to work using twitter-api-v2 like below:

export const auth: SvelteKitAuth = new SvelteKitAuth({
  ...
  providers: [
    ...
    new class extends TwitterAuthProvider {
      constructor() {
        super({
          apiKey: process.env.AUTH_TWITTER_API_KEY,
          apiSecret: process.env.AUTH_TWITTER_API_SECRET,
          profile: (profile) => {
            return { ...profile, provider: 'twitter' };
          },
        })
      }
      getRequestToken = async (auth, host): Promise<any> => {
        const { url, ...oauthResult } = await (new TwitterApi({
          appKey: this.config.apiKey,
          appSecret: this.config.apiSecret
        })).readOnly.generateAuthLink(
          encodeURIComponent(this.getCallbackUri()), { authAccessType: 'read' }
        );
        return {
          oauthToken: oauthResult.oauth_token,
          oauthTokenSecret: oauthResult.oauth_token_secret,
          oauthCallbackConfirmed: oauthResult.oauth_callback_confirmed
        };
      }
      getTokens = async (oauthToken: string, oauthVerifier: string): Promise<any> => {
        const endpoint = 'https://api.twitter.com/oauth/access_token';

        const data = {
          oauth_consumer_key: this.config.apiKey,
          oauth_token: oauthToken,
          oauth_verifier: oauthVerifier,
        };

        const response: any = await fetch(`${endpoint}?${new URLSearchParams(data)}`, { method: 'POST' });
        // This endpoint returns query string like key-value pairs
        // https://developer.twitter.com/en/docs/authentication/api-reference/access_token
        return Object.fromEntries([...(new URLSearchParams(await response.text()))]);
      }
      getUserProfile = async ({ oauth_token, oauth_token_secret, ...account }: any) => {
        let user: any = {};
        try {
          // Need to apply for elevated access - not tested yet
          user = await (new TwitterApi({
            appKey: this.config.apiKey,
            appSecret: this.config.apiSecret,
            accessToken: oauth_token,
            accessSecret: oauth_token_secret,
          })).readOnly.currentUser();
        } catch (e) {
          // 403
        }
        return { ...user, ...account };
      }
      getCallbackUri(): string {
        return `${settings.AUTH_CALLBACK_URI_PREFIX}twitter`;
      }
    },
    ...

Hey! When you mean using your own here. There's a reference to "new TwitterApi" in there. Where are you getting this from?

@nk113
Copy link

nk113 commented Jun 16, 2022

O sorry the link above doesn't work... I employed this twitter-api-v2 library
https://github.com/PLhery/node-twitter-api-v2
which is referred in
https://developer.twitter.com/en/docs/twitter-api/tools-and-libraries/v2

@caiges
Copy link

caiges commented Aug 16, 2022

I did something like this to support OAuth 1.0a with Twitter:

import { TwitterAuthProvider } from "sk-auth/providers";
import { TwitterApi } from 'twitter-api-v2';

const twitterProfileHandler = ({ id, id_str, name, screen_name, description, profile_image_url, profile_image_url_https, verified }) => ({
  id, id_str, name, screen_name, description, profile_image_url, profile_image_url_https, verified
});

const defaultConfig = {
  id: "twitter",
  profile: twitterProfileHandler,
}

export class TwitterV2AuthProvider extends TwitterAuthProvider {
  constructor(config) {
    super({
      ...defaultConfig,
      ...config
    })
  }
  async getRequestToken(auth, host, state) {
    const { url, ...oauthResult } = await (new TwitterApi({
      appKey: this.config.apiKey,
      appSecret: this.config.apiSecret
    })).readOnly.generateAuthLink(
      encodeURIComponent(this.getCallbackUri(auth, host, state)), { authAccessType: 'read' }
    );
    return {
      oauthToken: oauthResult.oauth_token,
      oauthTokenSecret: oauthResult.oauth_token_secret,
      oauthCallbackConfirmed: oauthResult.oauth_callback_confirmed
    };
  }
  getCallbackUri(svelteKitAuth, host, state) {
    return this.getUri(svelteKitAuth, `${"/callback/"}${this.id}?state=${state}`, host);
  }
  async getAuthorizationUrl({ url }, auth, state, nonce) {
    const endpoint = "https://api.twitter.com/oauth/authorize";
    const { oauthToken } = await this.getRequestToken(auth, url.host, state);
    const data = {
      oauth_token: oauthToken,
      redirect_uri: this.getCallbackUri(auth, url.host, state),
    };
    const authUrl = `${endpoint}?${new URLSearchParams(data)}`;
    return authUrl;
  }
  async getTokens(oauthToken, oauthVerifier) {
    const endpoint = 'https://api.twitter.com/oauth/access_token';

    const data = {
      oauth_consumer_key: this.config.apiKey,
      oauth_token: oauthToken,
      oauth_verifier: oauthVerifier,
    };

    const response = await fetch(`${endpoint}?${new URLSearchParams(data)}`, { method: 'POST' });
    // This endpoint returns query string like key-value pairs
    // https://developer.twitter.com/en/docs/authentication/api-reference/access_token
    return Object.fromEntries([...(new URLSearchParams(await response.text()))]);
  }
  async getUserProfile({ oauth_token, oauth_token_secret, ...account }) {
    let user = {};
    try {
      user = await (new TwitterApi({
        appKey: this.config.apiKey,
        appSecret: this.config.apiSecret,
        accessToken: oauth_token,
        accessSecret: oauth_token_secret,
      })).readOnly.currentUser();
    } catch (e) {
      console.error('could not get current user: ', e)
      return {};
    }

    return { ...user, ...account, oauth_token, oauth_token_secret };
  }
  async callback(event, auth) {
    const { url } = event;
    const oauthToken = url.searchParams.get("oauth_token");
    const oauthVerifier = url.searchParams.get("oauth_verifier");
    const redirect = this.getStateValue(url.searchParams, "redirect");
    const tokens = await this.getTokens(oauthToken, oauthVerifier);
    let user = await this.getUserProfile(tokens);
    if (this.config.profile) {
      user = await this.config.profile(user, tokens);
    }
    return [user, redirect ?? this.getUri(auth, "/", url.host)];
  }
}

TwitterV2AuthProvider.profileHandler = twitterProfileHandler;

and then incorporate it into my auth configuration:

export const appAuth = new SvelteKitAuth({
  protocol: import.meta.env.VITE_OAUTH_PROTOTCOL,
  providers: [
    new TwitterV2AuthProvider({
      apiKey: import.meta.env.VITE_TWITTER_API_KEY,
      apiSecret: import.meta.env.VITE_TWITTER_API_SECRET,
      profile: (profile, tokens) => {
        const slim = TwitterV2AuthProvider.profileHandler(profile);
        return { ...slim, tokens: { oauth_token: tokens.oauth_token, oauth_token_secret: tokens.oauth_token_secret }, provider: "twitter" };
      },
    }),
  ],
  callbacks: {
  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants