Skip to content

Commit 5c2cade

Browse files
committed
feat: enhance Discord strategy to support prompt option and improve scope fetching
1 parent 91c5574 commit 5c2cade

File tree

1 file changed

+62
-51
lines changed

1 file changed

+62
-51
lines changed

server/src/auth/strategies/discord.strategy/Strategy.ts

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Strategy as OAuth2Strategy,
77
StrategyOptions as OAuth2StrategyOptions,
88
VerifyCallback,
9+
VerifyFunction,
910
} from 'passport-oauth2';
1011

1112
import { DiscordStrategyConfig } from './DiscordStrategyConfig';
@@ -17,18 +18,8 @@ import {
1718
SingleScopeType,
1819
} from './types';
1920

20-
type VerifyFunction = (
21-
accessToken: string,
22-
refreshToken: string,
23-
profile: Profile,
24-
verified: VerifyCallback,
25-
) => void;
26-
2721
interface AuthorizationParams {
28-
permissions?: string;
2922
prompt?: string;
30-
disable_guild_select?: string;
31-
guild_id?: string;
3223
}
3324

3425
export default class Strategy extends OAuth2Strategy {
@@ -43,7 +34,7 @@ export default class Strategy extends OAuth2Strategy {
4334
private scopeDelay: number;
4435
private fetchScopeEnabled: boolean;
4536
public override name = 'discord';
46-
37+
prompt?: string;
4738
public constructor(options: DiscordStrategyConfig, verify: VerifyFunction) {
4839
super(
4940
{
@@ -60,6 +51,7 @@ export default class Strategy extends OAuth2Strategy {
6051
this.scopeDelay = options.scopeDelay ?? 0;
6152
this.fetchScopeEnabled = options.fetchScope ?? true;
6253
this._oauth2.useAuthorizationHeaderforGET(true);
54+
this.prompt = options.prompt;
6355
}
6456

6557
private async validateConfig(config: DiscordStrategyConfig): Promise<void> {
@@ -180,47 +172,68 @@ export default class Strategy extends OAuth2Strategy {
180172
};
181173
}
182174

183-
public async fetchScope(
175+
public fetchScope(
184176
scope: SingleScopeType,
185177
accessToken: string,
186-
): Promise<Record<string, unknown> | null> {
187-
if (!this.scope.includes(scope)) return null;
178+
callback: (err: Error | null, data: Record<string, unknown> | null) => void,
179+
): void {
180+
// Early return if scope is not included
181+
if (!this.scope.includes(scope)) {
182+
callback(null, null);
183+
return;
184+
}
188185

189-
await new Promise((resolve) => setTimeout(resolve, this.scopeDelay ?? 0));
186+
// Handle scope delay
187+
const delayPromise = new Promise<void>((resolve) =>
188+
setTimeout(resolve, this.scopeDelay ?? 0),
189+
);
190190

191-
return new Promise((resolve, reject) => {
192-
this._oauth2.get(
193-
`https://discord.com/api/users/@me/${scope}`,
194-
accessToken,
195-
(err, body) => {
196-
if (err) {
197-
return reject(
198-
new InternalOAuthError(
199-
`Failed to fetch the scope: ${scope}`,
200-
err,
201-
),
202-
);
203-
}
204-
205-
try {
206-
if (typeof body !== 'string') {
207-
return reject(
208-
new Error(`Failed to parse the returned scope data: ${scope}`),
191+
delayPromise
192+
.then(() => {
193+
this._oauth2.get(
194+
`${Strategy.DISCORD_API_BASE}/users/@me/${scope}`,
195+
accessToken,
196+
(err, body) => {
197+
if (err) {
198+
this.logger.error(`Failed to fetch scope ${scope}:`, err);
199+
200+
callback(
201+
new InternalOAuthError(`Failed to fetch scope: ${scope}`, err),
202+
null,
209203
);
204+
205+
return;
210206
}
211207

212-
const json = JSON.parse(body) as Record<string, unknown>;
213-
resolve(json);
214-
} catch (err) {
215-
this.logger.error(err);
216-
217-
reject(
218-
new Error(`Failed to parse the returned scope data: ${scope}`),
219-
);
220-
}
221-
},
222-
);
223-
});
208+
try {
209+
if (typeof body !== 'string') {
210+
const error = new Error(
211+
`Invalid response type for scope: ${scope}`,
212+
);
213+
214+
this.logger.error(error.message);
215+
callback(error, null);
216+
return;
217+
}
218+
219+
const json = JSON.parse(body) as Record<string, unknown>;
220+
callback(null, json);
221+
} catch (parseError) {
222+
const error =
223+
parseError instanceof Error
224+
? parseError
225+
: new Error(`Failed to parse scope data: ${scope}`);
226+
227+
this.logger.error('Parse error:', error);
228+
callback(error, null);
229+
}
230+
},
231+
);
232+
})
233+
.catch((error) => {
234+
this.logger.error('Unexpected error:', error);
235+
callback(error, null);
236+
});
224237
}
225238

226239
public override authorizationParams(
@@ -229,14 +242,12 @@ export default class Strategy extends OAuth2Strategy {
229242
const params: AuthorizationParams & Record<string, unknown> =
230243
super.authorizationParams(options) as Record<string, unknown>;
231244

232-
const { permissions, prompt, disable_guild_select, guild_id } = options;
233-
234-
if (permissions) params.permissions = permissions;
245+
const { prompt } = this;
235246
if (prompt) params.prompt = prompt;
236-
if (guild_id) params.guild_id = guild_id;
237-
if (disable_guild_select)
238-
params.disable_guild_select = disable_guild_select;
239247

248+
console.log('Authorization Params');
249+
console.log('params', params);
250+
console.log('options', options);
240251
return params;
241252
}
242253
}

0 commit comments

Comments
 (0)