mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
Handle start.gg OAuth token endpoint variants and robust errors
This commit is contained in:
+43
-18
@@ -4,8 +4,11 @@ import { getData, type CountryRecord } from 'country-list';
|
||||
import { nodecg } from './util/nodecg.js';
|
||||
|
||||
const STARTGG_ENDPOINT = 'https://api.start.gg/gql/alpha';
|
||||
const STARTGG_OAUTH_AUTHORIZE_ENDPOINT = 'https://api.start.gg/oauth/authorize';
|
||||
const STARTGG_OAUTH_TOKEN_ENDPOINT = 'https://api.start.gg/oauth/access_token';
|
||||
const STARTGG_OAUTH_AUTHORIZE_ENDPOINT = 'https://www.start.gg/api/-/rest/oauth/authorize';
|
||||
const STARTGG_OAUTH_TOKEN_ENDPOINTS = [
|
||||
'https://www.start.gg/api/-/rest/oauth/access_token',
|
||||
'https://api.start.gg/oauth/access_token',
|
||||
];
|
||||
const STARTGG_OAUTH_SCOPES = 'user.identity tournament.manager';
|
||||
const STARTGG_OAUTH_CALLBACK_PATH = '/startgg/callback';
|
||||
const STARTGG_OAUTH_DEFAULT_PORT = 34920;
|
||||
@@ -55,6 +58,7 @@ interface OAuthTokenResponse {
|
||||
access_token?: string;
|
||||
error?: string;
|
||||
error_description?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
const oauthSessions = new Map<string, OAuthSession>();
|
||||
@@ -163,6 +167,15 @@ const renderCallbackHtml = (title: string, message: string) => `<!doctype html>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const parseOAuthTokenPayload = async (response: Response): Promise<OAuthTokenResponse> => {
|
||||
const rawBody = await response.text();
|
||||
try {
|
||||
return JSON.parse(rawBody) as OAuthTokenResponse;
|
||||
} catch {
|
||||
return { message: rawBody };
|
||||
}
|
||||
};
|
||||
|
||||
const exchangeOAuthCodeForToken = async (
|
||||
code: string,
|
||||
redirectUri: string,
|
||||
@@ -176,25 +189,37 @@ const exchangeOAuthCodeForToken = async (
|
||||
redirect_uri: redirectUri,
|
||||
});
|
||||
|
||||
const response = await fetch(STARTGG_OAUTH_TOKEN_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: params.toString(),
|
||||
});
|
||||
let lastError = 'Unknown OAuth token exchange error';
|
||||
|
||||
const payload = (await response.json()) as OAuthTokenResponse;
|
||||
if (!response.ok) {
|
||||
throw new Error(payload.error_description || payload.error || `OAuth token request failed (${response.status})`);
|
||||
for (const tokenEndpoint of STARTGG_OAUTH_TOKEN_ENDPOINTS) {
|
||||
const response = await fetch(tokenEndpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: params.toString(),
|
||||
});
|
||||
|
||||
const payload = await parseOAuthTokenPayload(response);
|
||||
|
||||
if (response.ok) {
|
||||
const token = String(payload.access_token || '').trim();
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
|
||||
lastError = payload.error_description || payload.error || payload.message || 'OAuth token response did not include an access token';
|
||||
continue;
|
||||
}
|
||||
|
||||
lastError = payload.error_description || payload.error || payload.message || `OAuth token request failed (${response.status})`;
|
||||
|
||||
if (response.status !== 404) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const token = String(payload.access_token || '').trim();
|
||||
if (!token) {
|
||||
throw new Error('OAuth token response did not include an access token');
|
||||
}
|
||||
|
||||
return token;
|
||||
throw new Error(lastError);
|
||||
};
|
||||
|
||||
const ensureOAuthCallbackServer = async (oauthConfig: OAuthConfig) => {
|
||||
|
||||
Reference in New Issue
Block a user