feat: improved refresh mechanism
This commit is contained in:
parent
581953ba18
commit
b6da5b83e3
|
|
@ -28,6 +28,7 @@ import { NotEnoughScopesFilter } from '@gitroom/nestjs-libraries/integrations/in
|
|||
import { PostsService } from '@gitroom/nestjs-libraries/database/prisma/posts/posts.service';
|
||||
import { IntegrationTimeDto } from '@gitroom/nestjs-libraries/dtos/integrations/integration.time.dto';
|
||||
import { AuthService } from '@gitroom/helpers/auth/auth.service';
|
||||
import { AuthTokenDetails } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
|
||||
@ApiTags('Integrations')
|
||||
@Controller('/integrations')
|
||||
|
|
@ -156,7 +157,12 @@ export class IntegrationsController {
|
|||
: undefined;
|
||||
|
||||
const { codeVerifier, state, url } =
|
||||
await integrationProvider.generateAuthUrl(refresh, getExternalUrl);
|
||||
await integrationProvider.generateAuthUrl(getExternalUrl);
|
||||
|
||||
if (refresh) {
|
||||
await ioRedis.set(`refresh:${state}`, refresh, 'EX', 300);
|
||||
}
|
||||
|
||||
await ioRedis.set(`login:${state}`, codeVerifier, 'EX', 300);
|
||||
await ioRedis.set(
|
||||
`external:${state}`,
|
||||
|
|
@ -311,6 +317,11 @@ export class IntegrationsController {
|
|||
await ioRedis.del(`external:${body.state}`);
|
||||
}
|
||||
|
||||
const refresh = await ioRedis.get(`refresh:${body.state}`);
|
||||
if (refresh) {
|
||||
await ioRedis.del(`refresh:${body.state}`);
|
||||
}
|
||||
|
||||
const {
|
||||
accessToken,
|
||||
expiresIn,
|
||||
|
|
@ -319,14 +330,28 @@ export class IntegrationsController {
|
|||
name,
|
||||
picture,
|
||||
username,
|
||||
} = await integrationProvider.authenticate(
|
||||
{
|
||||
code: body.code,
|
||||
codeVerifier: getCodeVerifier,
|
||||
refresh: body.refresh,
|
||||
},
|
||||
details ? JSON.parse(details) : undefined
|
||||
);
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
} = await new Promise<AuthTokenDetails>(async (res) => {
|
||||
const auth = await integrationProvider.authenticate(
|
||||
{
|
||||
code: body.code,
|
||||
codeVerifier: getCodeVerifier,
|
||||
refresh: body.refresh,
|
||||
},
|
||||
details ? JSON.parse(details) : undefined
|
||||
);
|
||||
|
||||
if (refresh && integrationProvider.reConnect) {
|
||||
const newAuth = await integrationProvider.reConnect(
|
||||
auth.id,
|
||||
refresh,
|
||||
auth.accessToken
|
||||
);
|
||||
return res(newAuth);
|
||||
}
|
||||
|
||||
return res(auth);
|
||||
});
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Invalid api key');
|
||||
|
|
@ -343,7 +368,7 @@ export class IntegrationsController {
|
|||
refreshToken,
|
||||
expiresIn,
|
||||
username,
|
||||
integrationProvider.isBetweenSteps,
|
||||
refresh ? false : integrationProvider.isBetweenSteps,
|
||||
body.refresh,
|
||||
+body.timezone,
|
||||
details
|
||||
|
|
|
|||
|
|
@ -126,12 +126,13 @@ export const LaunchesComponent = () => {
|
|||
{sortedIntegrations.map((integration) => (
|
||||
<div
|
||||
{...(integration.refreshNeeded && {
|
||||
onClick: refreshChannel(integration),
|
||||
'data-tooltip-id': 'tooltip',
|
||||
'data-tooltip-content':
|
||||
'Channel disconnected, click to reconnect.',
|
||||
})}
|
||||
key={integration.id}
|
||||
className="flex gap-[8px] items-center"
|
||||
className={clsx("flex gap-[8px] items-center", integration.refreshNeeded && 'cursor-pointer')}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { FC, useCallback, useMemo } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
|
||||
import { continueProviderList } from '@gitroom/frontend/components/launches/providers/continue-provider/list';
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export abstract class SocialAbstract {
|
|||
let json = '{}';
|
||||
try {
|
||||
json = await request.text();
|
||||
console.log(json);
|
||||
} catch (err) {
|
||||
json = '{}';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export class BlueskyProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url: '',
|
||||
|
|
|
|||
|
|
@ -49,15 +49,13 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider {
|
|||
username: '',
|
||||
};
|
||||
}
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url: `https://discord.com/oauth2/authorize?client_id=${
|
||||
process.env.DISCORD_CLIENT_ID
|
||||
}&permissions=377957124096&response_type=code&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/discord${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/discord`
|
||||
)}&integration_type=0&scope=bot+identify+guilds&state=${state}`,
|
||||
codeVerifier: makeId(10),
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -75,15 +75,13 @@ export class DribbbleProvider extends SocialAbstract implements SocialProvider {
|
|||
);
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url: `https://dribbble.com/oauth/authorize?client_id=${
|
||||
process.env.DRIBBBLE_CLIENT_ID
|
||||
}&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/dribbble${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/dribbble`
|
||||
)}&response_type=code&scope=${this.scopes.join('+')}&state=${state}`,
|
||||
codeVerifier: makeId(10),
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
||||
import dayjs from 'dayjs';
|
||||
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { string } from 'yup';
|
||||
|
||||
export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
||||
identifier = 'facebook';
|
||||
|
|
@ -33,16 +34,14 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url:
|
||||
'https://www.facebook.com/v20.0/dialog/oauth' +
|
||||
`?client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/facebook${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/facebook`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
`&scope=${this.scopes.join(',')}`,
|
||||
|
|
@ -51,6 +50,27 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async reConnect(
|
||||
id: string,
|
||||
requiredId: string,
|
||||
accessToken: string
|
||||
): Promise<AuthTokenDetails> {
|
||||
const information = await this.fetchPageInformation(
|
||||
accessToken,
|
||||
requiredId
|
||||
);
|
||||
|
||||
return {
|
||||
id: information.id,
|
||||
name: information.name,
|
||||
accessToken: information.access_token,
|
||||
refreshToken: information.access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: information.picture,
|
||||
username: information.username,
|
||||
};
|
||||
}
|
||||
|
||||
async authenticate(params: {
|
||||
code: string;
|
||||
codeVerifier: string;
|
||||
|
|
@ -91,22 +111,6 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
|||
.map((p: any) => p.permission);
|
||||
this.checkScopes(this.scopes, permissions);
|
||||
|
||||
if (params.refresh) {
|
||||
const information = await this.fetchPageInformation(
|
||||
access_token,
|
||||
params.refresh
|
||||
);
|
||||
return {
|
||||
id: information.id,
|
||||
name: information.name,
|
||||
accessToken: information.access_token,
|
||||
refreshToken: information.access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: information.picture,
|
||||
username: information.username,
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
|
|
@ -174,7 +178,11 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {
|
|||
let finalId = '';
|
||||
let finalUrl = '';
|
||||
if ((firstPost?.media?.[0]?.url?.indexOf('mp4') || -2) > -1) {
|
||||
const { id: videoId, permalink_url, ...all } = await (
|
||||
const {
|
||||
id: videoId,
|
||||
permalink_url,
|
||||
...all
|
||||
} = await (
|
||||
await this.fetch(
|
||||
`https://graph.facebook.com/v20.0/${id}/videos?access_token=${accessToken}&fields=id,permalink_url`,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
|||
import { timer } from '@gitroom/helpers/utils/timer';
|
||||
import dayjs from 'dayjs';
|
||||
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { string } from 'yup';
|
||||
|
||||
export class InstagramProvider
|
||||
extends SocialAbstract
|
||||
|
|
@ -39,16 +40,39 @@ export class InstagramProvider
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async reConnect(
|
||||
id: string,
|
||||
requiredId: string,
|
||||
accessToken: string
|
||||
): Promise<AuthTokenDetails> {
|
||||
const findPage = (await this.pages(accessToken)).find(
|
||||
(p) => p.id === requiredId
|
||||
);
|
||||
|
||||
const information = await this.fetchPageInformation(accessToken, {
|
||||
id: requiredId,
|
||||
pageId: findPage?.pageId!,
|
||||
});
|
||||
|
||||
return {
|
||||
id: information.id,
|
||||
name: information.name,
|
||||
accessToken: information.access_token,
|
||||
refreshToken: information.access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: information.picture,
|
||||
username: information.username,
|
||||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url:
|
||||
'https://www.facebook.com/v20.0/dialog/oauth' +
|
||||
`?client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/instagram${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/instagram`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
`&scope=${encodeURIComponent(this.scopes.join(','))}`,
|
||||
|
|
@ -109,26 +133,6 @@ export class InstagramProvider
|
|||
)
|
||||
).json();
|
||||
|
||||
if (params.refresh) {
|
||||
const findPage = (await this.pages(access_token)).find(
|
||||
(p) => p.id === params.refresh
|
||||
);
|
||||
const information = await this.fetchPageInformation(access_token, {
|
||||
id: params.refresh,
|
||||
pageId: findPage?.pageId!,
|
||||
});
|
||||
|
||||
return {
|
||||
id: information.id,
|
||||
name: information.name,
|
||||
accessToken: information.access_token,
|
||||
refreshToken: information.access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: information.picture,
|
||||
username: information.username,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
|
|
@ -187,6 +191,7 @@ export class InstagramProvider
|
|||
)
|
||||
).json();
|
||||
|
||||
console.log(id, name, profile_picture_url, username);
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
|
|
@ -206,7 +211,9 @@ export class InstagramProvider
|
|||
const medias = await Promise.all(
|
||||
firstPost?.media?.map(async (m) => {
|
||||
const caption =
|
||||
firstPost.media?.length === 1 ? `&caption=${encodeURIComponent(firstPost.message)}` : ``;
|
||||
firstPost.media?.length === 1
|
||||
? `&caption=${encodeURIComponent(firstPost.message)}`
|
||||
: ``;
|
||||
const isCarousel =
|
||||
(firstPost?.media?.length || 0) > 1 ? `&is_carousel_item=true` : ``;
|
||||
const mediaType =
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ export class LinkedinPageProvider
|
|||
override async refreshToken(
|
||||
refresh_token: string
|
||||
): Promise<AuthTokenDetails> {
|
||||
const { access_token: accessToken, expires_in, refresh_token: refreshToken } = await (
|
||||
const {
|
||||
access_token: accessToken,
|
||||
expires_in,
|
||||
refresh_token: refreshToken,
|
||||
} = await (
|
||||
await fetch('https://www.linkedin.com/oauth/v2/accessToken', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -77,15 +81,13 @@ export class LinkedinPageProvider
|
|||
};
|
||||
}
|
||||
|
||||
override async generateAuthUrl(refresh?: string) {
|
||||
override async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
const codeVerifier = makeId(30);
|
||||
const url = `https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${
|
||||
process.env.LINKEDIN_CLIENT_ID
|
||||
}&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin-page${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin-page`
|
||||
)}&state=${state}&scope=${encodeURIComponent(this.scopes.join(' '))}`;
|
||||
return {
|
||||
url,
|
||||
|
|
@ -117,6 +119,24 @@ export class LinkedinPageProvider
|
|||
}));
|
||||
}
|
||||
|
||||
async reConnect(
|
||||
id: string,
|
||||
requiredId: string,
|
||||
accessToken: string
|
||||
): Promise<AuthTokenDetails> {
|
||||
const information = await this.fetchPageInformation(accessToken, requiredId);
|
||||
|
||||
return {
|
||||
id: information.id,
|
||||
name: information.name,
|
||||
accessToken: information.access_token,
|
||||
refreshToken: information.access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: information.picture,
|
||||
username: information.username,
|
||||
};
|
||||
}
|
||||
|
||||
async fetchPageInformation(accessToken: string, pageId: string) {
|
||||
const data = await (
|
||||
await fetch(
|
||||
|
|
@ -149,9 +169,7 @@ export class LinkedinPageProvider
|
|||
body.append('code', params.code);
|
||||
body.append(
|
||||
'redirect_uri',
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin-page${
|
||||
params.refresh ? `?refresh=${params.refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin-page`
|
||||
);
|
||||
body.append('client_id', process.env.LINKEDIN_CLIENT_ID!);
|
||||
body.append('client_secret', process.env.LINKEDIN_CLIENT_SECRET!);
|
||||
|
|
|
|||
|
|
@ -73,15 +73,13 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
const codeVerifier = makeId(30);
|
||||
const url = `https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${
|
||||
process.env.LINKEDIN_CLIENT_ID
|
||||
}&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/linkedin`
|
||||
)}&state=${state}&scope=${encodeURIComponent(this.scopes.join(' '))}`;
|
||||
return {
|
||||
url,
|
||||
|
|
|
|||
|
|
@ -29,24 +29,20 @@ export class MastodonProvider extends SocialAbstract implements SocialProvider {
|
|||
customUrl: string,
|
||||
state: string,
|
||||
clientId: string,
|
||||
url: string,
|
||||
refresh?: string
|
||||
url: string
|
||||
) {
|
||||
return `${customUrl}/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(
|
||||
`${url}/integrations/social/mastodon${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${url}/integrations/social/mastodon`
|
||||
)}&scope=${this.scopes.join('+')}&state=${state}`;
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
const url = this.generateUrlDynamic(
|
||||
'https://mastodon.social',
|
||||
state,
|
||||
process.env.MASTODON_CLIENT_ID!,
|
||||
process.env.FRONTEND_URL!,
|
||||
refresh
|
||||
process.env.FRONTEND_URL!
|
||||
);
|
||||
return {
|
||||
url,
|
||||
|
|
@ -98,13 +94,11 @@ export class MastodonProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async authenticate(
|
||||
params: {
|
||||
code: string;
|
||||
codeVerifier: string;
|
||||
refresh?: string;
|
||||
}
|
||||
) {
|
||||
async authenticate(params: {
|
||||
code: string;
|
||||
codeVerifier: string;
|
||||
refresh?: string;
|
||||
}) {
|
||||
return this.dynamicAuthenticate(
|
||||
process.env.MASTODON_CLIENT_ID!,
|
||||
process.env.MASTODON_CLIENT_SECRET!,
|
||||
|
|
|
|||
|
|
@ -67,15 +67,13 @@ export class PinterestProvider
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url: `https://www.pinterest.com/oauth/?client_id=${
|
||||
process.env.PINTEREST_CLIENT_ID
|
||||
}&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/pinterest${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
`${process.env.FRONTEND_URL}/integrations/social/pinterest`
|
||||
)}&response_type=code&scope=${encodeURIComponent(
|
||||
'boards:read,boards:write,pins:read,pins:write,user_accounts:read'
|
||||
)}&state=${state}`,
|
||||
|
|
@ -213,9 +211,7 @@ export class PinterestProvider
|
|||
}));
|
||||
|
||||
try {
|
||||
const {
|
||||
id: pId
|
||||
} = await (
|
||||
const { id: pId } = await (
|
||||
await this.fetch('https://api.pinterest.com/v5/pins', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export class SlackProvider extends SocialAbstract implements SocialProvider {
|
|||
username: '',
|
||||
};
|
||||
}
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
|
||||
return {
|
||||
|
|
@ -43,9 +43,7 @@ export class SlackProvider extends SocialAbstract implements SocialProvider {
|
|||
process?.env?.FRONTEND_URL?.indexOf('https') === -1
|
||||
? 'https://redirectmeto.com/'
|
||||
: ''
|
||||
}${process?.env?.FRONTEND_URL}/integrations/social/slack${
|
||||
refresh ? `?refresh=${refresh}` : ''
|
||||
}`
|
||||
}${process?.env?.FRONTEND_URL}/integrations/social/slack`
|
||||
)}&scope=channels:read,chat:write,users:read,groups:read,channels:join,chat:write.customize&state=${state}`,
|
||||
codeVerifier: makeId(10),
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ export interface IAuthenticator {
|
|||
clientInformation?: ClientInformation
|
||||
): Promise<AuthTokenDetails>;
|
||||
refreshToken(refreshToken: string): Promise<AuthTokenDetails>;
|
||||
reConnect?(id: string, requiredId: string, accessToken: string): Promise<AuthTokenDetails>;
|
||||
generateAuthUrl(
|
||||
refresh?: string,
|
||||
clientInformation?: ClientInformation
|
||||
): Promise<GenerateAuthUrlResponse>;
|
||||
analytics?(
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export class ThreadsProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = Math.random().toString(36).substring(2);
|
||||
|
||||
return {
|
||||
|
|
@ -79,7 +79,7 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider {
|
|||
process.env.NODE_ENV === 'development' || !process.env.NODE_ENV
|
||||
? `https://integration.git.sn/integrations/social/tiktok`
|
||||
: `${process.env.FRONTEND_URL}/integrations/social/tiktok`
|
||||
}${refresh ? `?refresh=${refresh}` : ''}`
|
||||
}`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
`&response_type=code` +
|
||||
|
|
|
|||
|
|
@ -49,15 +49,14 @@ export class XProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const client = new TwitterApi({
|
||||
appKey: process.env.X_API_KEY!,
|
||||
appSecret: process.env.X_API_SECRET!,
|
||||
});
|
||||
const { url, oauth_token, oauth_token_secret } =
|
||||
await client.generateAuthLink(
|
||||
process.env.FRONTEND_URL +
|
||||
`/integrations/social/x${refresh ? `?refresh=${refresh}` : ''}`,
|
||||
process.env.FRONTEND_URL + `/integrations/social/x`,
|
||||
{
|
||||
authAccessType: 'write',
|
||||
linkMode: 'authenticate',
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export class YoutubeProvider extends SocialAbstract implements SocialProvider {
|
|||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl(refresh?: string) {
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(7);
|
||||
const { client } = clientAndYoutube();
|
||||
return {
|
||||
|
|
|
|||
Loading…
Reference in New Issue