@eg-utils/client
v0.2.1
Published
Authenticated Epic Games HTTP client and device authorization CLI for Bun.
Maintainers
Readme
@eg-utils/client
Authenticated Epic Games HTTP requests, refresh-token persistence, and device authorization for Bun.
Installation
bun add @eg-utils/clientRequires Bun 1.3 or later. Tokens are stored in the operating system's credential store through Bun.secrets.
Bun.secrets uses Keychain Services on macOS, a Secret Service provider such as GNOME Keyring or KWallet on Linux, and Credential Manager on Windows. Bun currently describes this API as experimental, so applications should pin and test their supported Bun versions.
Authorize an account
The package installs an eg-authorize command:
bunx @eg-utils/client --id <client-id> --secret <client-secret>For a client tied to an Epic deployment:
bunx @eg-utils/client \
--deployment-id <deployment-id> \
--id <client-id> \
--secret <client-secret>For a legacy Epic service that requires the eg1 access-token format:
bunx @eg-utils/client \
--id <client-id> \
--secret <client-secret> \
--type eg1The command prints a one-time sign-in URL. After sign-in, it stores the token under the authenticated Epic account ID and OAuth client ID. It does not print the token or secret.
Authorization is also available as an API:
import { authorize } from '@eg-utils/client';
const { accountId } = await authorize({
id: process.env.EPIC_CLIENT_ID!,
secret: process.env.EPIC_CLIENT_SECRET!,
tokenType: 'eg1',
onVerification: (url) => console.log(`Sign in: ${url}`),
});
console.log(`Authorized ${accountId}`);Use Client directly
Create a client with the same OAuth application and the account ID printed by the authorization command:
import Client from '@eg-utils/client';
const accountId = '<epic-account-id>';
const launcherApp2Client = new Client({
accountId,
id: process.env.EPIC_CLIENT_ID!,
secret: process.env.EPIC_CLIENT_SECRET!,
tokenType: 'eg1',
});
const response = await launcherApp2Client.fetch(
`https://account-public-service-prod.ol.epicgames.com/account/api/public/account/${accountId}`,
);
if (!response.ok) {
throw new Error(`Epic request failed: ${response.status} ${await response.text()}`);
}
const account = await response.json();
console.log(account);client.fetch follows the standard Fetch API and adds a current bearer token unless the request already has an Authorization header. Requests that provide their own authorization do not read the stored Epic token. Access tokens are refreshed shortly before expiration and saved automatically. Concurrent loads, refreshes, saves, and deletes are deduplicated per client instance.
If an OAuth application requires a deployment or the legacy Epic Games eg1 token form, pass deploymentId or tokenType: 'eg1' to both authorize and the Client constructor. Access tokens are refreshed 30 seconds before expiration by default; pass tokenRefreshBuffer in milliseconds to change that window, or set it to 0 to disable early refresh.
Extend Client
Extend Client when an application needs fixed OAuth credentials, typed events, or service-specific request methods. The subclass can call this.fetch(...) for requests that need the stored Epic token:
import Client from '@eg-utils/client';
export namespace AccountsClient {
export type EventMap = {
request: [url: string];
};
}
export class AccountsClient extends Client<AccountsClient.EventMap> {
public constructor(accountId: string) {
super({
accountId,
id: process.env.EPIC_CLIENT_ID!,
secret: process.env.EPIC_CLIENT_SECRET!,
});
}
public async getAccount(): Promise<unknown> {
const url = `https://api.epicgames.dev/epic/id/v1/accounts?accountId=${this.accountId}`;
this.emit('request', url);
const response = await this.fetch(url);
if (!response.ok) {
throw new Error(`Epic request failed: ${response.status} ${await response.text()}`);
}
return response.json();
}
}
const client = new AccountsClient('<epic-account-id>');
console.log(await client.getAccount());Token storage
The OAuth client ID is used as the credential-store service and the Epic account ID is used as the credential name. Large tokens are split into integrity-checked chunks to fit credential-store limits. A replacement token is committed only after all of its chunks have been written.
To remove a stored token:
await client.delete();Exports
The default and named Client exports are equivalent. authorize, runAuthorizeCLI, and their public types are exported from the package root and from @eg-utils/client/authorize.
Development
bun install
bun run checkLicense
This project is not affiliated with or endorsed by Epic Games, Inc.
