Open saneef opened 3 years ago
I hadn't enabled Enable 3-legged OAuth
on Twitter 🤦♂️
Sorry.
Even after enabling 3-legged OAuth
on Twitter, I'm facing this issue? Any clues?
I have the same issue - with OAuth v1 and v2.
Did you managed to make it work?
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. So which one and how to use?
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`;
}
},
...
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?
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
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: {
...
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
.