convex-auth-battlenet 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Juan Hander
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # convex-auth-battlenet
2
+
3
+ Battle.net OAuth provider for [Convex Auth](https://labs.convex.dev/auth).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install convex-auth-battlenet
9
+ # or
10
+ bun add convex-auth-battlenet
11
+ ```
12
+
13
+ ## Setup
14
+
15
+ ### 1. Create a Battle.net Application
16
+
17
+ 1. Go to the [Battle.net Developer Portal](https://develop.battle.net/)
18
+ 2. Create a new application
19
+ 3. Set the redirect URI to `https://your-convex-site.convex.site/api/auth/callback/battlenet`
20
+ 4. Copy the Client ID and Client Secret
21
+
22
+ ### 2. Configure Environment Variables
23
+
24
+ Add to your Convex environment (via dashboard or CLI):
25
+
26
+ ```bash
27
+ AUTH_BATTLENET_ID=your_client_id
28
+ AUTH_BATTLENET_SECRET=your_client_secret
29
+ ```
30
+
31
+ ### 3. Add to Convex Auth
32
+
33
+ ```typescript
34
+ // convex/auth.ts
35
+ import { convexAuth } from "@convex-dev/auth/server";
36
+ import { BattleNet } from "convex-auth-battlenet";
37
+
38
+ export const { auth, signIn, signOut, store } = convexAuth({
39
+ providers: [BattleNet()],
40
+ });
41
+ ```
42
+
43
+ That's it! No custom schema or callbacks required.
44
+
45
+ ## Configuration Options
46
+
47
+ ```typescript
48
+ BattleNet({
49
+ // OAuth issuer URL (for China region use "https://oauth.battlenet.com.cn")
50
+ // Default: "https://oauth.battle.net"
51
+ issuer: "https://oauth.battlenet.com.cn",
52
+
53
+ // Override client credentials (optional, reads from env vars by default)
54
+ clientId: "your_client_id",
55
+ clientSecret: "your_client_secret",
56
+ });
57
+ ```
58
+
59
+ ## Frontend Usage
60
+
61
+ ```tsx
62
+ import { useAuthActions } from "@convex-dev/auth/react";
63
+
64
+ function LoginButton() {
65
+ const { signIn } = useAuthActions();
66
+
67
+ return (
68
+ <button onClick={() => signIn("battlenet")}>
69
+ Sign in with Battle.net
70
+ </button>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ## User Profile
76
+
77
+ The provider maps the Battle.net profile to:
78
+
79
+ | Field | Source |
80
+ |-------|--------|
81
+ | `id` | `sub` (unique identifier) |
82
+ | `name` | `battletag` (e.g., "Player#1234") |
83
+ | `email` | Synthetic email (`{sub}@battlenet.oauth`) |
84
+
85
+ > **Note:** Battle.net doesn't provide real email addresses. A synthetic email is generated for Convex Auth compatibility. This email cannot receive messages.
86
+
87
+ ## TypeScript
88
+
89
+ Full TypeScript support with exported types:
90
+
91
+ ```typescript
92
+ import type {
93
+ BattleNetConfig,
94
+ BattleNetProfile,
95
+ BattleNetIssuer,
96
+ } from "convex-auth-battlenet";
97
+ ```
98
+
99
+ ## License
100
+
101
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ // src/provider.ts
4
+ var OAUTH_BASE = "https://oauth.battle.net";
5
+ function BattleNet(config) {
6
+ const { issuer, clientId, clientSecret, ...rest } = config ?? {};
7
+ const base = issuer ?? OAUTH_BASE;
8
+ return {
9
+ id: "battlenet",
10
+ name: "Battle.net",
11
+ type: "oauth",
12
+ clientId: clientId ?? process.env.AUTH_BATTLENET_ID,
13
+ clientSecret: clientSecret ?? process.env.AUTH_BATTLENET_SECRET,
14
+ authorization: {
15
+ url: `${base}/authorize`,
16
+ params: { scope: "openid" }
17
+ },
18
+ token: {
19
+ url: `${base}/token`,
20
+ async conform(response) {
21
+ const data = await response.json();
22
+ delete data.id_token;
23
+ return new Response(JSON.stringify(data), {
24
+ status: response.status,
25
+ headers: { "Content-Type": "application/json" }
26
+ });
27
+ }
28
+ },
29
+ userinfo: {
30
+ url: `${base}/userinfo`,
31
+ async request({ tokens }) {
32
+ const response = await fetch(`${base}/userinfo`, {
33
+ headers: {
34
+ Authorization: `Bearer ${tokens.access_token}`,
35
+ Accept: "application/json"
36
+ }
37
+ });
38
+ if (!response.ok) {
39
+ throw new Error(`Userinfo request failed: ${response.status}`);
40
+ }
41
+ return response.json();
42
+ }
43
+ },
44
+ checks: ["state", "pkce"],
45
+ client: { token_endpoint_auth_method: "client_secret_post" },
46
+ profile(profile) {
47
+ return {
48
+ id: profile.sub,
49
+ name: profile.battletag ?? profile.battle_tag,
50
+ // Synthetic email for Convex Auth compatibility (Battle.net doesn't provide emails)
51
+ email: `${profile.sub}@battlenet.oauth`
52
+ };
53
+ },
54
+ style: { bg: "#148eff", text: "#fff" },
55
+ ...rest
56
+ };
57
+ }
58
+
59
+ exports.BattleNet = BattleNet;
60
+ //# sourceMappingURL=index.cjs.map
61
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/provider.ts"],"names":[],"mappings":";;;AAGA,IAAM,UAAA,GAAa,0BAAA;AAqBZ,SAAS,UACd,MAAA,EAC+B;AAC/B,EAAA,MAAM,EAAE,QAAQ,QAAA,EAAU,YAAA,EAAc,GAAG,IAAA,EAAK,GAAI,UAAU,EAAC;AAC/D,EAAA,MAAM,OAAO,MAAA,IAAU,UAAA;AAEvB,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,WAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM,OAAA;AAAA,IACN,QAAA,EAAU,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,iBAAA;AAAA,IAClC,YAAA,EAAc,YAAA,IAAgB,OAAA,CAAQ,GAAA,CAAI,qBAAA;AAAA,IAC1C,aAAA,EAAe;AAAA,MACb,GAAA,EAAK,GAAG,IAAI,CAAA,UAAA,CAAA;AAAA,MACZ,MAAA,EAAQ,EAAE,KAAA,EAAO,QAAA;AAAS,KAC5B;AAAA,IACA,KAAA,EAAO;AAAA,MACL,GAAA,EAAK,GAAG,IAAI,CAAA,MAAA,CAAA;AAAA,MACZ,MAAM,QAAQ,QAAA,EAAoB;AAehC,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,OAAO,IAAA,CAAK,QAAA;AACZ,QAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,UACxC,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,SAC/C,CAAA;AAAA,MACH;AAAA,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,GAAA,EAAK,GAAG,IAAI,CAAA,SAAA,CAAA;AAAA,MACZ,MAAM,OAAA,CAAQ,EAAE,MAAA,EAAO,EAA0C;AAC/D,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,SAAA,CAAA,EAAa;AAAA,UAC/C,OAAA,EAAS;AAAA,YACP,aAAA,EAAe,CAAA,OAAA,EAAU,MAAA,CAAO,YAAY,CAAA,CAAA;AAAA,YAC5C,MAAA,EAAQ;AAAA;AACV,SACD,CAAA;AACD,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,QAC/D;AACA,QAAA,OAAO,SAAS,IAAA,EAAK;AAAA,MACvB;AAAA,KACF;AAAA,IACA,MAAA,EAAQ,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA,IACxB,MAAA,EAAQ,EAAE,0BAAA,EAA4B,oBAAA,EAAqB;AAAA,IAC3D,QAAQ,OAAA,EAA2B;AACjC,MAAA,OAAO;AAAA,QACL,IAAI,OAAA,CAAQ,GAAA;AAAA,QACZ,IAAA,EAAM,OAAA,CAAQ,SAAA,IAAa,OAAA,CAAQ,UAAA;AAAA;AAAA,QAEnC,KAAA,EAAO,CAAA,EAAG,OAAA,CAAQ,GAAG,CAAA,gBAAA;AAAA,OACvB;AAAA,IACF,CAAA;AAAA,IACA,KAAA,EAAO,EAAE,EAAA,EAAI,SAAA,EAAW,MAAM,MAAA,EAAO;AAAA,IACrC,GAAG;AAAA,GACL;AACF","file":"index.cjs","sourcesContent":["import type { OAuthConfig, OAuthUserConfig } from \"@auth/core/providers\";\nimport type { BattleNetConfig, BattleNetProfile } from \"./types.js\";\n\nconst OAUTH_BASE = \"https://oauth.battle.net\";\n\n/**\n * Battle.net OAuth provider for Convex Auth\n *\n * Works out-of-the-box with Convex Auth's default schema. Since Battle.net\n * doesn't provide email addresses, a synthetic email is generated using\n * the user's unique ID (e.g., \"12345@battlenet.oauth\").\n *\n * @example\n * ```ts\n * import { convexAuth } from \"@convex-dev/auth/server\";\n * import { BattleNet } from \"convex-auth-battlenet\";\n *\n * export const { auth, signIn, signOut, store } = convexAuth({\n * providers: [BattleNet()],\n * });\n * ```\n *\n * @see https://develop.battle.net/documentation/guides/using-oauth\n */\nexport function BattleNet(\n config?: BattleNetConfig & Partial<OAuthUserConfig<BattleNetProfile>>\n): OAuthConfig<BattleNetProfile> {\n const { issuer, clientId, clientSecret, ...rest } = config ?? {};\n const base = issuer ?? OAUTH_BASE;\n\n return {\n id: \"battlenet\",\n name: \"Battle.net\",\n type: \"oauth\",\n clientId: clientId ?? process.env.AUTH_BATTLENET_ID,\n clientSecret: clientSecret ?? process.env.AUTH_BATTLENET_SECRET,\n authorization: {\n url: `${base}/authorize`,\n params: { scope: \"openid\" },\n },\n token: {\n url: `${base}/token`,\n async conform(response: Response) {\n /**\n * Battle.net returns an id_token even though we only request the \"openid\" scope.\n * The oauth4webapi library (used by @auth/core) performs strict nonce validation\n * on id_tokens, but Battle.net's id_token doesn't always pass this validation.\n *\n * Since we're using the OAuth 2.0 authorization code flow (not pure OIDC),\n * we don't need the id_token - we fetch user info directly from the userinfo\n * endpoint using the access_token instead.\n *\n * This is a safe workaround because:\n * 1. We use PKCE + state for request validation\n * 2. User identity is verified via the userinfo endpoint\n * 3. The access_token is sufficient for our authentication needs\n */\n const data = await response.json();\n delete data.id_token;\n return new Response(JSON.stringify(data), {\n status: response.status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n },\n },\n userinfo: {\n url: `${base}/userinfo`,\n async request({ tokens }: { tokens: { access_token?: string } }) {\n const response = await fetch(`${base}/userinfo`, {\n headers: {\n Authorization: `Bearer ${tokens.access_token}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n throw new Error(`Userinfo request failed: ${response.status}`);\n }\n return response.json();\n },\n },\n checks: [\"state\", \"pkce\"],\n client: { token_endpoint_auth_method: \"client_secret_post\" },\n profile(profile: BattleNetProfile) {\n return {\n id: profile.sub,\n name: profile.battletag ?? profile.battle_tag,\n // Synthetic email for Convex Auth compatibility (Battle.net doesn't provide emails)\n email: `${profile.sub}@battlenet.oauth`,\n };\n },\n style: { bg: \"#148eff\", text: \"#fff\" },\n ...rest,\n } as OAuthConfig<BattleNetProfile>;\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import { OAuthUserConfig, OAuthConfig } from '@auth/core/providers';
2
+
3
+ /**
4
+ * Battle.net OAuth issuer URLs
5
+ * - Global: https://oauth.battle.net
6
+ * - China: https://oauth.battlenet.com.cn
7
+ */
8
+ type BattleNetIssuer = "https://oauth.battle.net" | "https://oauth.battlenet.com.cn";
9
+ /**
10
+ * Battle.net user profile from the userinfo endpoint
11
+ */
12
+ interface BattleNetProfile extends Record<string, unknown> {
13
+ /** Unique user identifier */
14
+ sub: string;
15
+ /** BattleTag (e.g., "Player#1234") */
16
+ battletag?: string;
17
+ /** Alternative BattleTag field name */
18
+ battle_tag?: string;
19
+ }
20
+ /**
21
+ * Configuration options for the BattleNet provider
22
+ */
23
+ interface BattleNetConfig {
24
+ /**
25
+ * OAuth issuer URL
26
+ * @default "https://oauth.battle.net"
27
+ */
28
+ issuer?: BattleNetIssuer;
29
+ /**
30
+ * OAuth client ID (falls back to AUTH_BATTLENET_ID env var)
31
+ */
32
+ clientId?: string;
33
+ /**
34
+ * OAuth client secret (falls back to AUTH_BATTLENET_SECRET env var)
35
+ */
36
+ clientSecret?: string;
37
+ }
38
+
39
+ /**
40
+ * Battle.net OAuth provider for Convex Auth
41
+ *
42
+ * Works out-of-the-box with Convex Auth's default schema. Since Battle.net
43
+ * doesn't provide email addresses, a synthetic email is generated using
44
+ * the user's unique ID (e.g., "12345@battlenet.oauth").
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { convexAuth } from "@convex-dev/auth/server";
49
+ * import { BattleNet } from "convex-auth-battlenet";
50
+ *
51
+ * export const { auth, signIn, signOut, store } = convexAuth({
52
+ * providers: [BattleNet()],
53
+ * });
54
+ * ```
55
+ *
56
+ * @see https://develop.battle.net/documentation/guides/using-oauth
57
+ */
58
+ declare function BattleNet(config?: BattleNetConfig & Partial<OAuthUserConfig<BattleNetProfile>>): OAuthConfig<BattleNetProfile>;
59
+
60
+ export { BattleNet, type BattleNetConfig, type BattleNetIssuer, type BattleNetProfile };
@@ -0,0 +1,60 @@
1
+ import { OAuthUserConfig, OAuthConfig } from '@auth/core/providers';
2
+
3
+ /**
4
+ * Battle.net OAuth issuer URLs
5
+ * - Global: https://oauth.battle.net
6
+ * - China: https://oauth.battlenet.com.cn
7
+ */
8
+ type BattleNetIssuer = "https://oauth.battle.net" | "https://oauth.battlenet.com.cn";
9
+ /**
10
+ * Battle.net user profile from the userinfo endpoint
11
+ */
12
+ interface BattleNetProfile extends Record<string, unknown> {
13
+ /** Unique user identifier */
14
+ sub: string;
15
+ /** BattleTag (e.g., "Player#1234") */
16
+ battletag?: string;
17
+ /** Alternative BattleTag field name */
18
+ battle_tag?: string;
19
+ }
20
+ /**
21
+ * Configuration options for the BattleNet provider
22
+ */
23
+ interface BattleNetConfig {
24
+ /**
25
+ * OAuth issuer URL
26
+ * @default "https://oauth.battle.net"
27
+ */
28
+ issuer?: BattleNetIssuer;
29
+ /**
30
+ * OAuth client ID (falls back to AUTH_BATTLENET_ID env var)
31
+ */
32
+ clientId?: string;
33
+ /**
34
+ * OAuth client secret (falls back to AUTH_BATTLENET_SECRET env var)
35
+ */
36
+ clientSecret?: string;
37
+ }
38
+
39
+ /**
40
+ * Battle.net OAuth provider for Convex Auth
41
+ *
42
+ * Works out-of-the-box with Convex Auth's default schema. Since Battle.net
43
+ * doesn't provide email addresses, a synthetic email is generated using
44
+ * the user's unique ID (e.g., "12345@battlenet.oauth").
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { convexAuth } from "@convex-dev/auth/server";
49
+ * import { BattleNet } from "convex-auth-battlenet";
50
+ *
51
+ * export const { auth, signIn, signOut, store } = convexAuth({
52
+ * providers: [BattleNet()],
53
+ * });
54
+ * ```
55
+ *
56
+ * @see https://develop.battle.net/documentation/guides/using-oauth
57
+ */
58
+ declare function BattleNet(config?: BattleNetConfig & Partial<OAuthUserConfig<BattleNetProfile>>): OAuthConfig<BattleNetProfile>;
59
+
60
+ export { BattleNet, type BattleNetConfig, type BattleNetIssuer, type BattleNetProfile };
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ // src/provider.ts
2
+ var OAUTH_BASE = "https://oauth.battle.net";
3
+ function BattleNet(config) {
4
+ const { issuer, clientId, clientSecret, ...rest } = config ?? {};
5
+ const base = issuer ?? OAUTH_BASE;
6
+ return {
7
+ id: "battlenet",
8
+ name: "Battle.net",
9
+ type: "oauth",
10
+ clientId: clientId ?? process.env.AUTH_BATTLENET_ID,
11
+ clientSecret: clientSecret ?? process.env.AUTH_BATTLENET_SECRET,
12
+ authorization: {
13
+ url: `${base}/authorize`,
14
+ params: { scope: "openid" }
15
+ },
16
+ token: {
17
+ url: `${base}/token`,
18
+ async conform(response) {
19
+ const data = await response.json();
20
+ delete data.id_token;
21
+ return new Response(JSON.stringify(data), {
22
+ status: response.status,
23
+ headers: { "Content-Type": "application/json" }
24
+ });
25
+ }
26
+ },
27
+ userinfo: {
28
+ url: `${base}/userinfo`,
29
+ async request({ tokens }) {
30
+ const response = await fetch(`${base}/userinfo`, {
31
+ headers: {
32
+ Authorization: `Bearer ${tokens.access_token}`,
33
+ Accept: "application/json"
34
+ }
35
+ });
36
+ if (!response.ok) {
37
+ throw new Error(`Userinfo request failed: ${response.status}`);
38
+ }
39
+ return response.json();
40
+ }
41
+ },
42
+ checks: ["state", "pkce"],
43
+ client: { token_endpoint_auth_method: "client_secret_post" },
44
+ profile(profile) {
45
+ return {
46
+ id: profile.sub,
47
+ name: profile.battletag ?? profile.battle_tag,
48
+ // Synthetic email for Convex Auth compatibility (Battle.net doesn't provide emails)
49
+ email: `${profile.sub}@battlenet.oauth`
50
+ };
51
+ },
52
+ style: { bg: "#148eff", text: "#fff" },
53
+ ...rest
54
+ };
55
+ }
56
+
57
+ export { BattleNet };
58
+ //# sourceMappingURL=index.js.map
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/provider.ts"],"names":[],"mappings":";AAGA,IAAM,UAAA,GAAa,0BAAA;AAqBZ,SAAS,UACd,MAAA,EAC+B;AAC/B,EAAA,MAAM,EAAE,QAAQ,QAAA,EAAU,YAAA,EAAc,GAAG,IAAA,EAAK,GAAI,UAAU,EAAC;AAC/D,EAAA,MAAM,OAAO,MAAA,IAAU,UAAA;AAEvB,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,WAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM,OAAA;AAAA,IACN,QAAA,EAAU,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,iBAAA;AAAA,IAClC,YAAA,EAAc,YAAA,IAAgB,OAAA,CAAQ,GAAA,CAAI,qBAAA;AAAA,IAC1C,aAAA,EAAe;AAAA,MACb,GAAA,EAAK,GAAG,IAAI,CAAA,UAAA,CAAA;AAAA,MACZ,MAAA,EAAQ,EAAE,KAAA,EAAO,QAAA;AAAS,KAC5B;AAAA,IACA,KAAA,EAAO;AAAA,MACL,GAAA,EAAK,GAAG,IAAI,CAAA,MAAA,CAAA;AAAA,MACZ,MAAM,QAAQ,QAAA,EAAoB;AAehC,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,OAAO,IAAA,CAAK,QAAA;AACZ,QAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,UACxC,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,SAC/C,CAAA;AAAA,MACH;AAAA,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,GAAA,EAAK,GAAG,IAAI,CAAA,SAAA,CAAA;AAAA,MACZ,MAAM,OAAA,CAAQ,EAAE,MAAA,EAAO,EAA0C;AAC/D,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,SAAA,CAAA,EAAa;AAAA,UAC/C,OAAA,EAAS;AAAA,YACP,aAAA,EAAe,CAAA,OAAA,EAAU,MAAA,CAAO,YAAY,CAAA,CAAA;AAAA,YAC5C,MAAA,EAAQ;AAAA;AACV,SACD,CAAA;AACD,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,QAC/D;AACA,QAAA,OAAO,SAAS,IAAA,EAAK;AAAA,MACvB;AAAA,KACF;AAAA,IACA,MAAA,EAAQ,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA,IACxB,MAAA,EAAQ,EAAE,0BAAA,EAA4B,oBAAA,EAAqB;AAAA,IAC3D,QAAQ,OAAA,EAA2B;AACjC,MAAA,OAAO;AAAA,QACL,IAAI,OAAA,CAAQ,GAAA;AAAA,QACZ,IAAA,EAAM,OAAA,CAAQ,SAAA,IAAa,OAAA,CAAQ,UAAA;AAAA;AAAA,QAEnC,KAAA,EAAO,CAAA,EAAG,OAAA,CAAQ,GAAG,CAAA,gBAAA;AAAA,OACvB;AAAA,IACF,CAAA;AAAA,IACA,KAAA,EAAO,EAAE,EAAA,EAAI,SAAA,EAAW,MAAM,MAAA,EAAO;AAAA,IACrC,GAAG;AAAA,GACL;AACF","file":"index.js","sourcesContent":["import type { OAuthConfig, OAuthUserConfig } from \"@auth/core/providers\";\nimport type { BattleNetConfig, BattleNetProfile } from \"./types.js\";\n\nconst OAUTH_BASE = \"https://oauth.battle.net\";\n\n/**\n * Battle.net OAuth provider for Convex Auth\n *\n * Works out-of-the-box with Convex Auth's default schema. Since Battle.net\n * doesn't provide email addresses, a synthetic email is generated using\n * the user's unique ID (e.g., \"12345@battlenet.oauth\").\n *\n * @example\n * ```ts\n * import { convexAuth } from \"@convex-dev/auth/server\";\n * import { BattleNet } from \"convex-auth-battlenet\";\n *\n * export const { auth, signIn, signOut, store } = convexAuth({\n * providers: [BattleNet()],\n * });\n * ```\n *\n * @see https://develop.battle.net/documentation/guides/using-oauth\n */\nexport function BattleNet(\n config?: BattleNetConfig & Partial<OAuthUserConfig<BattleNetProfile>>\n): OAuthConfig<BattleNetProfile> {\n const { issuer, clientId, clientSecret, ...rest } = config ?? {};\n const base = issuer ?? OAUTH_BASE;\n\n return {\n id: \"battlenet\",\n name: \"Battle.net\",\n type: \"oauth\",\n clientId: clientId ?? process.env.AUTH_BATTLENET_ID,\n clientSecret: clientSecret ?? process.env.AUTH_BATTLENET_SECRET,\n authorization: {\n url: `${base}/authorize`,\n params: { scope: \"openid\" },\n },\n token: {\n url: `${base}/token`,\n async conform(response: Response) {\n /**\n * Battle.net returns an id_token even though we only request the \"openid\" scope.\n * The oauth4webapi library (used by @auth/core) performs strict nonce validation\n * on id_tokens, but Battle.net's id_token doesn't always pass this validation.\n *\n * Since we're using the OAuth 2.0 authorization code flow (not pure OIDC),\n * we don't need the id_token - we fetch user info directly from the userinfo\n * endpoint using the access_token instead.\n *\n * This is a safe workaround because:\n * 1. We use PKCE + state for request validation\n * 2. User identity is verified via the userinfo endpoint\n * 3. The access_token is sufficient for our authentication needs\n */\n const data = await response.json();\n delete data.id_token;\n return new Response(JSON.stringify(data), {\n status: response.status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n },\n },\n userinfo: {\n url: `${base}/userinfo`,\n async request({ tokens }: { tokens: { access_token?: string } }) {\n const response = await fetch(`${base}/userinfo`, {\n headers: {\n Authorization: `Bearer ${tokens.access_token}`,\n Accept: \"application/json\",\n },\n });\n if (!response.ok) {\n throw new Error(`Userinfo request failed: ${response.status}`);\n }\n return response.json();\n },\n },\n checks: [\"state\", \"pkce\"],\n client: { token_endpoint_auth_method: \"client_secret_post\" },\n profile(profile: BattleNetProfile) {\n return {\n id: profile.sub,\n name: profile.battletag ?? profile.battle_tag,\n // Synthetic email for Convex Auth compatibility (Battle.net doesn't provide emails)\n email: `${profile.sub}@battlenet.oauth`,\n };\n },\n style: { bg: \"#148eff\", text: \"#fff\" },\n ...rest,\n } as OAuthConfig<BattleNetProfile>;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "convex-auth-battlenet",
3
+ "version": "0.1.0",
4
+ "description": "Battle.net OAuth provider for Convex Auth",
5
+ "author": "Juan Hander",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.cts",
19
+ "default": "./dist/index.cjs"
20
+ }
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch",
29
+ "test": "bun test",
30
+ "typecheck": "tsc --noEmit",
31
+ "prepublishOnly": "bun run build && bun run test"
32
+ },
33
+ "keywords": [
34
+ "convex",
35
+ "auth",
36
+ "battlenet",
37
+ "battle.net",
38
+ "blizzard",
39
+ "oauth",
40
+ "authentication"
41
+ ],
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/juanhander/convex-auth-battlenet"
45
+ },
46
+ "peerDependencies": {
47
+ "@auth/core": ">=0.35.0",
48
+ "@convex-dev/auth": ">=0.0.71"
49
+ },
50
+ "devDependencies": {
51
+ "@auth/core": "^0.37.0",
52
+ "@convex-dev/auth": "^0.0.80",
53
+ "@types/bun": "^1.3.6",
54
+ "tsup": "^8.4.0",
55
+ "typescript": "^5.9.3"
56
+ }
57
+ }