diff --git a/.github/ISSUE_TEMPLATE/2_bug_provider.yml b/.github/ISSUE_TEMPLATE/2_bug_provider.yml index a63162241b..2262c5a536 100644 --- a/.github/ISSUE_TEMPLATE/2_bug_provider.yml +++ b/.github/ISSUE_TEMPLATE/2_bug_provider.yml @@ -45,6 +45,7 @@ body: - "Discord" - "Dribbble" - "Dropbox" + - "Epic Games" - "Eventbrite" - "EVE Online" - "Facebook" diff --git a/docs/pages/data/manifest.json b/docs/pages/data/manifest.json index 4724fa10aa..606b418151 100644 --- a/docs/pages/data/manifest.json +++ b/docs/pages/data/manifest.json @@ -71,6 +71,7 @@ "dribbble": "Dribbble", "dropbox": "Dropbox", "duende-identityserver-6": "DuendeIdentityServer6", + "epicgames": "Epic Games", "eveonline": "EVE Online", "faceit": "FACEIT", "figma": "Figma", diff --git a/docs/public/img/providers/epicgames.svg b/docs/public/img/providers/epicgames.svg new file mode 100644 index 0000000000..725f2e7e41 --- /dev/null +++ b/docs/public/img/providers/epicgames.svg @@ -0,0 +1,53 @@ + + + + + + + + + + diff --git a/packages/core/src/providers/epicgames.ts b/packages/core/src/providers/epicgames.ts new file mode 100644 index 0000000000..b521490085 --- /dev/null +++ b/packages/core/src/providers/epicgames.ts @@ -0,0 +1,142 @@ +/** + *
+ * Built-in Epic Games integration. + * + * + * + *
+ * + * @module providers/epicgames + */ + +/** + * @provider EpicGames + * + * Epic Games OAuth Provider for Auth.js + * + * This provider uses OAuth 2.0 to authenticate users with their Epic Games account. + * + * @see [Epic Games OAuth Documentation] + * (https://dev.epicgames.com/docs/services/en-US/EpicAccountServices) + * @see [Auth.js OAuth Providers Guide](https://authjs.dev/guides/configuring-oauth-providers) + * + * @example + * ```ts + * import EpicGamesProvider from "next-auth/providers/epicgames" + * + * export default NextAuth({ + * providers: [ + * EpicGamesProvider({ + * clientId: process.env.EPIC_CLIENT_ID, + * clientSecret: process.env.EPIC_CLIENT_SECRET, + * }) + * ] + * }) + * ``` + * + * ### Environment Variables + * + * - `EPIC_CLIENT_ID` + * - `EPIC_CLIENT_SECRET` + * + * ### Profile Response + * + * The Epic Games profile has the following structure: + * + * ```json + * { + * "sub": "user_id_123", + * "preferred_username": "EpicUser123" + * } + * ``` + */ + +import type { OAuthConfig, OAuthUserConfig } from "./index.js" + +/** + * The shape of the user object returned by Epic Games when requesting user info. + * Properties must be adapted based on the exact data the client decides to receive from the Epic Games API. + */ +export interface EpicGamesProfile { + sub: string + preferred_username?: string + // preferred_language?: string; +} + +/** + * Configure the Epic Games OAuth provider. + * + * @param {OAuthUserConfig} options - User configuration for the Epic Games provider + * @returns {OAuthConfig} - An object conforming to the Auth.js OAuthConfig interface + * + * @example + * ```ts + * import EpicGamesProvider from "next-auth/providers/epicgames" + * // ... + * providers: [ + * EpicGamesProvider({ + * clientId: process.env.EPIC_CLIENT_ID, + * clientSecret: process.env.EPIC_CLIENT_SECRET, + * }) + * ] + * ``` + */ +export default function EpicGamesProvider

( + options: OAuthUserConfig

+): OAuthConfig

{ + return { + id: "epicgames", + name: "Epic Games", + type: "oauth", + authorization: { + url: "https://www.epicgames.com/id/authorize", + params: { + scope: "profile friends_list country", + response_type: "code", + }, + }, + + token: { + url: "https://api.epicgames.dev/epic/oauth/v2/token", + async request(context) { + const basicAuth = Buffer.from( + `${context.provider.clientId}:${context.provider.clientSecret}` + ).toString("base64") + + const res = await fetch( + "https://api.epicgames.dev/epic/oauth/v2/token", + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: context.params.code!, + redirect_uri: context.provider.callbackUrl, + }), + } + ) + + const tokens = await res.json() + if (!res.ok) throw new Error(JSON.stringify(tokens)) + + return { tokens } + }, + }, + + userinfo: "https://api.epicgames.dev/epic/oauth/v2/userInfo", + + profile(profile: P) { + return { + id: profile.sub, + name: profile.preferred_username ?? profile.sub, + } + }, + + checks: ["state"], + clientId: options.clientId, + clientSecret: options.clientSecret, + } +}