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';
|
import { nodecg } from './util/nodecg.js';
|
||||||
|
|
||||||
const STARTGG_ENDPOINT = 'https://api.start.gg/gql/alpha';
|
const STARTGG_ENDPOINT = 'https://api.start.gg/gql/alpha';
|
||||||
const STARTGG_OAUTH_AUTHORIZE_ENDPOINT = 'https://api.start.gg/oauth/authorize';
|
const STARTGG_OAUTH_AUTHORIZE_ENDPOINT = 'https://www.start.gg/api/-/rest/oauth/authorize';
|
||||||
const STARTGG_OAUTH_TOKEN_ENDPOINT = 'https://api.start.gg/oauth/access_token';
|
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_SCOPES = 'user.identity tournament.manager';
|
||||||
const STARTGG_OAUTH_CALLBACK_PATH = '/startgg/callback';
|
const STARTGG_OAUTH_CALLBACK_PATH = '/startgg/callback';
|
||||||
const STARTGG_OAUTH_DEFAULT_PORT = 34920;
|
const STARTGG_OAUTH_DEFAULT_PORT = 34920;
|
||||||
@@ -55,6 +58,7 @@ interface OAuthTokenResponse {
|
|||||||
access_token?: string;
|
access_token?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
error_description?: string;
|
error_description?: string;
|
||||||
|
message?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const oauthSessions = new Map<string, OAuthSession>();
|
const oauthSessions = new Map<string, OAuthSession>();
|
||||||
@@ -163,6 +167,15 @@ const renderCallbackHtml = (title: string, message: string) => `<!doctype html>
|
|||||||
</body>
|
</body>
|
||||||
</html>`;
|
</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 (
|
const exchangeOAuthCodeForToken = async (
|
||||||
code: string,
|
code: string,
|
||||||
redirectUri: string,
|
redirectUri: string,
|
||||||
@@ -176,25 +189,37 @@ const exchangeOAuthCodeForToken = async (
|
|||||||
redirect_uri: redirectUri,
|
redirect_uri: redirectUri,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await fetch(STARTGG_OAUTH_TOKEN_ENDPOINT, {
|
let lastError = 'Unknown OAuth token exchange error';
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
body: params.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const payload = (await response.json()) as OAuthTokenResponse;
|
for (const tokenEndpoint of STARTGG_OAUTH_TOKEN_ENDPOINTS) {
|
||||||
if (!response.ok) {
|
const response = await fetch(tokenEndpoint, {
|
||||||
throw new Error(payload.error_description || payload.error || `OAuth token request failed (${response.status})`);
|
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();
|
throw new Error(lastError);
|
||||||
if (!token) {
|
|
||||||
throw new Error('OAuth token response did not include an access token');
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ensureOAuthCallbackServer = async (oauthConfig: OAuthConfig) => {
|
const ensureOAuthCallbackServer = async (oauthConfig: OAuthConfig) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user