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 +21 -0
- package/README.md +101 -0
- package/dist/index.cjs +61 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|