refactor(api): restructure Epic Games OAuth flow with new client credentials step
The OAuth device flow has been refactored to use the client credentials grant flow as the first step, followed by a proper device authorization request using the obtained client credentials token. This change modernizes the authentication flow to align with current Epic Games OAuth requirements and replaces the previous direct device authorization approach that used client_id and client_secret in the request body with the standardized authorization header pattern.
This commit is contained in:
parent
e8c28db63d
commit
d4acc813bc
1 changed files with 67 additions and 27 deletions
|
|
@ -47,11 +47,16 @@ const fetchFreeGamesAPI = async () => {
|
|||
const pollForTokens = async (deviceCode, maxAttempts = 30) => {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
try {
|
||||
const response = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token', {
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
||||
device_code: deviceCode,
|
||||
client_id: '98f7e42c2e3a4f86a74eb43fbb41ed39',
|
||||
client_secret: '0a2449a2-001a-451e-afec-3e812901c4d7',
|
||||
const params = new URLSearchParams();
|
||||
params.append('grant_type', 'urn:ietf:params:oauth:grant-type:device_code');
|
||||
params.append('device_code', deviceCode);
|
||||
params.append('client_id', '98f7e42c2e3a4f86a74eb43fbb41ed39');
|
||||
params.append('client_secret', '0a2449a2-001a-451e-afec-3e812901c4d7');
|
||||
|
||||
const response = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token', params.toString(), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
if (response.data?.access_token) {
|
||||
console.log('✅ OAuth successful');
|
||||
|
|
@ -84,6 +89,48 @@ const exchangeTokenForCookies = async accessToken => {
|
|||
return cookies;
|
||||
};
|
||||
|
||||
// Get client credentials token (first step of OAuth flow)
|
||||
const getClientCredentialsToken = async () => {
|
||||
try {
|
||||
const response = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token', {
|
||||
grant_type: 'client_credentials',
|
||||
}, {
|
||||
auth: {
|
||||
username: '98f7e42c2e3a4f86a74eb43fbb41ed39',
|
||||
password: '0a2449a2-001a-451e-afec-3e812901c4d7',
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
return response.data.access_token;
|
||||
} catch (error) {
|
||||
console.error('Failed to get client credentials token:', error.response?.status || error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get device authorization code (second step of OAuth flow)
|
||||
const getDeviceAuthorizationCode = async (clientCredentialsToken) => {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('prompt', 'login');
|
||||
|
||||
const response = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/deviceAuthorization', params.toString(), {
|
||||
headers: {
|
||||
Authorization: `Bearer ${clientCredentialsToken}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
console.log('Device authorization response:', response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to get device authorization code:', error.response?.status || error.message);
|
||||
console.error('Error response data:', error.response?.data);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get valid authentication
|
||||
const getValidAuth = async ({ otpKey, reuseCookies, cookiesPath }) => {
|
||||
if (reuseCookies && existsSync(cookiesPath)) {
|
||||
|
|
@ -96,25 +143,13 @@ const getValidAuth = async ({ otpKey, reuseCookies, cookiesPath }) => {
|
|||
}
|
||||
|
||||
console.log('🔐 Starting fresh OAuth device flow (manual approval required)...');
|
||||
let deviceResponse;
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('clientId', '98f7e42c2e3a4f86a74eb43fbb41ed39');
|
||||
params.append('clientSecret', '0a2449a2-001a-451e-afec-3e812901c4d7');
|
||||
params.append('scope', 'account.basicprofile account.userentitlements');
|
||||
// Step 1: Get client credentials token
|
||||
const clientCredentialsToken = await getClientCredentialsToken();
|
||||
console.log('✅ Got client credentials token');
|
||||
|
||||
deviceResponse = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/deviceAuthorization', params.toString(), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Device code flow failed (fallback to manual login):', error.response?.status || error.message);
|
||||
return { bearerToken: null, cookies: [] };
|
||||
}
|
||||
|
||||
const { deviceCode, userCode, verificationUriComplete } = deviceResponse.data;
|
||||
// Step 2: Get device authorization code
|
||||
const { deviceCode, userCode, verificationUriComplete } = await getDeviceAuthorizationCode(clientCredentialsToken);
|
||||
console.log(`📱 Open: ${verificationUriComplete}`);
|
||||
console.log(`💳 Code: ${userCode}`);
|
||||
|
||||
|
|
@ -124,11 +159,16 @@ const getValidAuth = async ({ otpKey, reuseCookies, cookiesPath }) => {
|
|||
const totpCode = authenticator.generate(otpKey);
|
||||
console.log(`🔑 TOTP Code (generated): ${totpCode}`);
|
||||
try {
|
||||
const refreshed = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token', {
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: tokens.refresh_token,
|
||||
client_id: '98f7e42c2e3a4f86a74eb43fbb41ed39',
|
||||
client_secret: '0a2449a2-001a-451e-afec-3e812901c4d7',
|
||||
const params = new URLSearchParams();
|
||||
params.append('grant_type', 'refresh_token');
|
||||
params.append('refresh_token', tokens.refresh_token);
|
||||
params.append('client_id', '98f7e42c2e3a4f86a74eb43fbb41ed39');
|
||||
params.append('client_secret', '0a2449a2-001a-451e-afec-3e812901c4d7');
|
||||
|
||||
const refreshed = await axios.post('https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token', params.toString(), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
tokens.access_token = refreshed.data.access_token;
|
||||
} catch {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue