@shware/security 0.4.6 → 0.4.7
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/dist/oauth2/provider/common.cjs +4 -8
- package/dist/oauth2/provider/common.cjs.map +1 -1
- package/dist/oauth2/provider/common.d.cts +2 -5
- package/dist/oauth2/provider/common.d.ts +2 -5
- package/dist/oauth2/provider/common.mjs +1 -4
- package/dist/oauth2/provider/common.mjs.map +1 -1
- package/dist/oauth2/provider/x.cjs +1 -2
- package/dist/oauth2/provider/x.cjs.map +1 -1
- package/dist/oauth2/provider/x.mjs +1 -3
- package/dist/oauth2/provider/x.mjs.map +1 -1
- package/package.json +1 -2
|
@@ -32,7 +32,6 @@ var common_exports = {};
|
|
|
32
32
|
__export(common_exports, {
|
|
33
33
|
createAuthorizationUri: () => createAuthorizationUri,
|
|
34
34
|
exchangeAuthorizationCode: () => exchangeAuthorizationCode,
|
|
35
|
-
proxyAgent: () => proxyAgent,
|
|
36
35
|
refreshAccessToken: () => refreshAccessToken,
|
|
37
36
|
revokeToken: () => revokeToken,
|
|
38
37
|
verifyIdToken: () => verifyIdToken
|
|
@@ -40,7 +39,6 @@ __export(common_exports, {
|
|
|
40
39
|
module.exports = __toCommonJS(common_exports);
|
|
41
40
|
var import_crypto = require("crypto");
|
|
42
41
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
43
|
-
var import_undici = require("undici");
|
|
44
42
|
var import_error = require("../error.cjs");
|
|
45
43
|
function createAuthorizationUri(options) {
|
|
46
44
|
const url = new URL(options.authorizationUri);
|
|
@@ -56,7 +54,6 @@ function createAuthorizationUri(options) {
|
|
|
56
54
|
}
|
|
57
55
|
return url;
|
|
58
56
|
}
|
|
59
|
-
var proxyAgent = new import_undici.ProxyAgent("http://localhost:7890");
|
|
60
57
|
async function exchangeAuthorizationCode(params) {
|
|
61
58
|
const body = new URLSearchParams();
|
|
62
59
|
body.append("code", params.code);
|
|
@@ -74,7 +71,7 @@ async function exchangeAuthorizationCode(params) {
|
|
|
74
71
|
body.append("client_id", params.clientId);
|
|
75
72
|
body.append("client_secret", params.clientSecret);
|
|
76
73
|
}
|
|
77
|
-
return
|
|
74
|
+
return fetch(params.tokenUri, { method: "POST", headers, body });
|
|
78
75
|
}
|
|
79
76
|
async function refreshAccessToken(params) {
|
|
80
77
|
const body = new URLSearchParams();
|
|
@@ -91,7 +88,7 @@ async function refreshAccessToken(params) {
|
|
|
91
88
|
body.append("client_id", params.clientId);
|
|
92
89
|
body.append("client_secret", params.clientSecret);
|
|
93
90
|
}
|
|
94
|
-
const response = await
|
|
91
|
+
const response = await fetch(params.tokenUri, { method: "POST", headers, body });
|
|
95
92
|
if (!response.ok) {
|
|
96
93
|
const error = await response.json();
|
|
97
94
|
console.error("Refresh token error:", error);
|
|
@@ -113,7 +110,7 @@ async function revokeToken(params) {
|
|
|
113
110
|
body.append("client_id", params.clientId);
|
|
114
111
|
body.append("client_secret", params.clientSecret);
|
|
115
112
|
}
|
|
116
|
-
const response = await
|
|
113
|
+
const response = await fetch(params.tokenRevokeUri, { method: "POST", headers, body });
|
|
117
114
|
if (!response.ok) {
|
|
118
115
|
const error = await response.json();
|
|
119
116
|
console.error("Refresh token error:", error);
|
|
@@ -126,7 +123,7 @@ async function getJWK(kid, jwkSetUri) {
|
|
|
126
123
|
if (cache.has(jwkSetUri)) {
|
|
127
124
|
jwkSet = cache.get(jwkSetUri);
|
|
128
125
|
} else {
|
|
129
|
-
const response = await
|
|
126
|
+
const response = await fetch(jwkSetUri);
|
|
130
127
|
if (!response.ok) throw new import_error.OAuth2Error(response.status, "server_error", "Failed to fetch JWK");
|
|
131
128
|
jwkSet = await response.json();
|
|
132
129
|
cache.set(jwkSetUri, jwkSet);
|
|
@@ -151,7 +148,6 @@ async function verifyIdToken(idToken, jwkSetUri) {
|
|
|
151
148
|
0 && (module.exports = {
|
|
152
149
|
createAuthorizationUri,
|
|
153
150
|
exchangeAuthorizationCode,
|
|
154
|
-
proxyAgent,
|
|
155
151
|
refreshAccessToken,
|
|
156
152
|
revokeToken,
|
|
157
153
|
verifyIdToken
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport { OAuth2Error } from '../error';\nimport { CodeExchangeParams, OAuth2Token } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n codeVerifier?: string;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.codeVerifier) {\n const codeChallenge = createHash('sha256')\n .update(options.codeVerifier)\n .digest()\n .toString('base64url');\n url.searchParams.append('code_challenge_method', 'S256');\n url.searchParams.append('code_challenge', codeChallenge);\n }\n return url;\n}\n\ninterface Params extends CodeExchangeParams {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function exchangeAuthorizationCode(params: Params) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.codeVerifier) body.append('code_verifier', params.codeVerifier);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RefreshTokenParams {\n tokenUri: string;\n clientId: string;\n clientSecret: string;\n refreshToken: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function refreshAccessToken(params: RefreshTokenParams) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to refresh token');\n }\n return (await response.json()) as OAuth2Token;\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\ninterface JWKSet {\n keys: { kty: string; kid: string; use: string; alg: string; n: string; e: string }[];\n}\n\nconst cache = new Map<string, JWKSet>();\n\nasync function getJWK(kid: string, jwkSetUri: string) {\n let jwkSet: JWKSet;\n if (cache.has(jwkSetUri)) {\n jwkSet = cache.get(jwkSetUri)!;\n } else {\n const response = await fetch(jwkSetUri);\n if (!response.ok) throw new OAuth2Error(response.status, 'server_error', 'Failed to fetch JWK');\n jwkSet = (await response.json()) as JWKSet;\n cache.set(jwkSetUri, jwkSet);\n }\n\n const jwk = jwkSet.keys.find((key) => key.kid === kid);\n if (!jwk) throw new OAuth2Error(400, 'invalid_request', `JWK not found for kid: ${kid}`);\n return jwk;\n}\n\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n const header = jwt.decode(idToken, { complete: true });\n if (!header?.header.kid) {\n throw new OAuth2Error(400, 'invalid_request', 'kid not found in id_token header');\n }\n try {\n const key = await getJWK(header.header.kid, jwkSetUri);\n return jwt.verify(idToken, { key, format: 'jwk' }) as T;\n } catch (e) {\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":["jwt"]}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as undici from 'undici';
|
|
2
|
-
import { ProxyAgent } from 'undici';
|
|
3
1
|
import * as url from 'url';
|
|
4
2
|
import { CodeExchangeParams, OAuth2Token } from '../types.cjs';
|
|
5
3
|
|
|
@@ -15,8 +13,7 @@ interface Params extends CodeExchangeParams {
|
|
|
15
13
|
tokenUri: string;
|
|
16
14
|
authentication?: 'basic' | 'post';
|
|
17
15
|
}
|
|
18
|
-
declare
|
|
19
|
-
declare function exchangeAuthorizationCode(params: Params): Promise<undici.Response>;
|
|
16
|
+
declare function exchangeAuthorizationCode(params: Params): Promise<Response>;
|
|
20
17
|
interface RefreshTokenParams {
|
|
21
18
|
tokenUri: string;
|
|
22
19
|
clientId: string;
|
|
@@ -35,4 +32,4 @@ interface RevokeTokenParams {
|
|
|
35
32
|
declare function revokeToken(params: RevokeTokenParams): Promise<void>;
|
|
36
33
|
declare function verifyIdToken<T>(idToken: string, jwkSetUri: string): Promise<T>;
|
|
37
34
|
|
|
38
|
-
export { createAuthorizationUri, exchangeAuthorizationCode,
|
|
35
|
+
export { createAuthorizationUri, exchangeAuthorizationCode, refreshAccessToken, revokeToken, verifyIdToken };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as undici from 'undici';
|
|
2
|
-
import { ProxyAgent } from 'undici';
|
|
3
1
|
import * as url from 'url';
|
|
4
2
|
import { CodeExchangeParams, OAuth2Token } from '../types.js';
|
|
5
3
|
|
|
@@ -15,8 +13,7 @@ interface Params extends CodeExchangeParams {
|
|
|
15
13
|
tokenUri: string;
|
|
16
14
|
authentication?: 'basic' | 'post';
|
|
17
15
|
}
|
|
18
|
-
declare
|
|
19
|
-
declare function exchangeAuthorizationCode(params: Params): Promise<undici.Response>;
|
|
16
|
+
declare function exchangeAuthorizationCode(params: Params): Promise<Response>;
|
|
20
17
|
interface RefreshTokenParams {
|
|
21
18
|
tokenUri: string;
|
|
22
19
|
clientId: string;
|
|
@@ -35,4 +32,4 @@ interface RevokeTokenParams {
|
|
|
35
32
|
declare function revokeToken(params: RevokeTokenParams): Promise<void>;
|
|
36
33
|
declare function verifyIdToken<T>(idToken: string, jwkSetUri: string): Promise<T>;
|
|
37
34
|
|
|
38
|
-
export { createAuthorizationUri, exchangeAuthorizationCode,
|
|
35
|
+
export { createAuthorizationUri, exchangeAuthorizationCode, refreshAccessToken, revokeToken, verifyIdToken };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// src/oauth2/provider/common.ts
|
|
2
2
|
import { createHash } from "crypto";
|
|
3
3
|
import jwt from "jsonwebtoken";
|
|
4
|
-
import { fetch, ProxyAgent } from "undici";
|
|
5
4
|
import { OAuth2Error } from "../error.mjs";
|
|
6
5
|
function createAuthorizationUri(options) {
|
|
7
6
|
const url = new URL(options.authorizationUri);
|
|
@@ -17,7 +16,6 @@ function createAuthorizationUri(options) {
|
|
|
17
16
|
}
|
|
18
17
|
return url;
|
|
19
18
|
}
|
|
20
|
-
var proxyAgent = new ProxyAgent("http://localhost:7890");
|
|
21
19
|
async function exchangeAuthorizationCode(params) {
|
|
22
20
|
const body = new URLSearchParams();
|
|
23
21
|
body.append("code", params.code);
|
|
@@ -35,7 +33,7 @@ async function exchangeAuthorizationCode(params) {
|
|
|
35
33
|
body.append("client_id", params.clientId);
|
|
36
34
|
body.append("client_secret", params.clientSecret);
|
|
37
35
|
}
|
|
38
|
-
return fetch(params.tokenUri, { method: "POST", headers, body
|
|
36
|
+
return fetch(params.tokenUri, { method: "POST", headers, body });
|
|
39
37
|
}
|
|
40
38
|
async function refreshAccessToken(params) {
|
|
41
39
|
const body = new URLSearchParams();
|
|
@@ -111,7 +109,6 @@ async function verifyIdToken(idToken, jwkSetUri) {
|
|
|
111
109
|
export {
|
|
112
110
|
createAuthorizationUri,
|
|
113
111
|
exchangeAuthorizationCode,
|
|
114
|
-
proxyAgent,
|
|
115
112
|
refreshAccessToken,
|
|
116
113
|
revokeToken,
|
|
117
114
|
verifyIdToken
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport { OAuth2Error } from '../error';\nimport { CodeExchangeParams, OAuth2Token } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n codeVerifier?: string;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.codeVerifier) {\n const codeChallenge = createHash('sha256')\n .update(options.codeVerifier)\n .digest()\n .toString('base64url');\n url.searchParams.append('code_challenge_method', 'S256');\n url.searchParams.append('code_challenge', codeChallenge);\n }\n return url;\n}\n\ninterface Params extends CodeExchangeParams {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function exchangeAuthorizationCode(params: Params) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.codeVerifier) body.append('code_verifier', params.codeVerifier);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RefreshTokenParams {\n tokenUri: string;\n clientId: string;\n clientSecret: string;\n refreshToken: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function refreshAccessToken(params: RefreshTokenParams) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to refresh token');\n }\n return (await response.json()) as OAuth2Token;\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\ninterface JWKSet {\n keys: { kty: string; kid: string; use: string; alg: string; n: string; e: string }[];\n}\n\nconst cache = new Map<string, JWKSet>();\n\nasync function getJWK(kid: string, jwkSetUri: string) {\n let jwkSet: JWKSet;\n if (cache.has(jwkSetUri)) {\n jwkSet = cache.get(jwkSetUri)!;\n } else {\n const response = await fetch(jwkSetUri);\n if (!response.ok) throw new OAuth2Error(response.status, 'server_error', 'Failed to fetch JWK');\n jwkSet = (await response.json()) as JWKSet;\n cache.set(jwkSetUri, jwkSet);\n }\n\n const jwk = jwkSet.keys.find((key) => key.kid === kid);\n if (!jwk) throw new OAuth2Error(400, 'invalid_request', `JWK not found for kid: ${kid}`);\n return jwk;\n}\n\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n const header = jwt.decode(idToken, { complete: true });\n if (!header?.header.kid) {\n throw new OAuth2Error(400, 'invalid_request', 'kid not found in id_token header');\n }\n try {\n const key = await getJWK(header.header.kid, jwkSetUri);\n return jwt.verify(idToken, { key, format: 'jwk' }) as T;\n } catch (e) {\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -34,7 +34,6 @@ __export(x_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(x_exports);
|
|
36
36
|
var import_tiny_invariant = __toESM(require("tiny-invariant"), 1);
|
|
37
|
-
var import_undici = require("undici");
|
|
38
37
|
var import_error = require("../error.cjs");
|
|
39
38
|
var import_common = require("./common.cjs");
|
|
40
39
|
var defaultUserFields = [
|
|
@@ -82,7 +81,7 @@ function x(options) {
|
|
|
82
81
|
const headers = { Accept: "application/json", Authorization: `Bearer ${access_token}` };
|
|
83
82
|
const url = new URL(this.userInfoUri);
|
|
84
83
|
userFields.forEach((field) => url.searchParams.append("user.fields", field));
|
|
85
|
-
const response = await
|
|
84
|
+
const response = await fetch(this.userInfoUri, { headers });
|
|
86
85
|
if (!response.ok) {
|
|
87
86
|
const { errors } = await response.json();
|
|
88
87
|
throw new import_error.OAuth2Error(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import invariant from 'tiny-invariant';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import invariant from 'tiny-invariant';\nimport { Provider } from '../types';\nimport { OAuth2Error } from '../error';\nimport {\n createAuthorizationUri,\n exchangeAuthorizationCode,\n refreshAccessToken,\n revokeToken,\n} from './common';\n\nexport interface XOptions {\n userFields?: UserField[];\n}\n\nconst defaultUserFields = [\n 'id',\n 'name',\n 'profile_image_url',\n 'url',\n 'username',\n 'location',\n 'verified',\n];\n\nexport function x(options?: XOptions): Provider<XUserInfo> {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRevokeUri: 'https://api.x.com/2/oauth2/revoke',\n // https://docs.x.com/x-api/users/user-lookup-me\n userInfoUri: 'https://api.x.com/2/users/me',\n defaultScope: ['users.read', 'tweet.read', 'offline.access'],\n createAuthorizationUri(params) {\n if (!params.codeVerifier) throw new Error('codeVerifier is required for x');\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode(params) {\n if (!params.codeVerifier) throw new Error('codeVerifier is required for x');\n const response = await exchangeAuthorizationCode({\n ...params,\n tokenUri: this.tokenUri,\n authentication: 'basic',\n });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as XErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as XOAuth2Token;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const userFields = options?.userFields ?? defaultUserFields;\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n\n const url = new URL(this.userInfoUri);\n userFields.forEach((field) => url.searchParams.append('user.fields', field));\n\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n const { errors } = (await response.json()) as XAPIErrorResponse;\n throw new OAuth2Error(\n response.status,\n 'invalid_request',\n 'Failed to fetch user info: ' + (errors.at(0)?.detail ?? errors.at(0)?.title)\n );\n }\n const profile = (await response.json()) as XUserInfo;\n return {\n data: profile,\n claims: {\n sub: profile.data.id,\n name: profile.data.name,\n picture: profile.data.profile_image_url,\n email: profile.data.email,\n email_verified: profile.data.verified || false,\n preferred_username: profile.data.username,\n profile: `https://x.com/${profile.data.username}`,\n website: profile.data.url,\n },\n };\n },\n async refreshAccessToken(params) {\n return refreshAccessToken({ ...params, tokenUri: this.tokenUri, authentication: 'basic' });\n },\n async revokeToken(params) {\n invariant(this.tokenRevokeUri, 'tokenRevokeUri is required');\n return revokeToken({\n ...params,\n tokenRevokeUri: this.tokenRevokeUri,\n authentication: 'basic',\n });\n },\n };\n}\n\ntype UserField =\n | 'affiliation'\n | 'connection_status'\n | 'created_at'\n | 'description'\n | 'entities'\n | 'id'\n | 'is_identity_verified'\n | 'location'\n | 'most_recent_tweet_id'\n | 'name'\n | 'parody'\n | 'pinned_tweet_id'\n | 'profile_banner_url'\n | 'profile_image_url'\n | 'protected'\n | 'public_metrics'\n | 'receives_your_dm'\n | 'subscription'\n | 'subscription_type'\n | 'url'\n | 'username'\n | 'verified'\n | 'verified_followers_count'\n | 'verified_type'\n | 'withheld';\n\nexport interface XUser {\n id: string;\n name: string;\n email?: string;\n username: string;\n location?: string;\n entities?: {\n url: { urls: UrlEntity[] };\n description: {\n hashtags: HashtagEntity[];\n cashtags: HashtagEntity[];\n mentions: MentionEntity[];\n };\n };\n verified?: boolean;\n description?: string;\n url?: string;\n profile_image_url?: string;\n protected?: boolean;\n pinned_tweet_id?: string;\n created_at?: string;\n}\n\nexport interface XUserInfo {\n data: XUser;\n includes?: { tweets?: { id: string; text: string }[]; users?: XUser[] };\n}\n\n// prettier-ignore\ntype UrlEntity = { start: number; end: number; url: string; display_url: string; expanded_url: string; }\ntype HashtagEntity = { start: number; end: number; tag: string };\ntype MentionEntity = { start: number; end: string; username: string };\n\ntype XOAuth2Token = {\n token_type: string;\n expires_in: number;\n access_token: string;\n scope: string;\n refresh_token: string;\n};\n\ntype XErrorResponse = { error: string; error_description: string };\ntype XAPIErrorResponse = {\n errors: { title: string; type: string; detail?: string; status?: number }[];\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAsB;AAEtB,mBAA4B;AAC5B,oBAKO;AAMP,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,EAAE,SAAyC;AACzD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,gBAAgB;AAAA;AAAA,IAEhB,aAAa;AAAA,IACb,cAAc,CAAC,cAAc,cAAc,gBAAgB;AAAA,IAC3D,uBAAuB,QAAQ;AAC7B,UAAI,CAAC,OAAO,aAAc,OAAM,IAAI,MAAM,gCAAgC;AAC1E,iBAAO,sCAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,QAAQ;AACtC,UAAI,CAAC,OAAO,aAAc,OAAM,IAAI,MAAM,gCAAgC;AAC1E,YAAM,WAAW,UAAM,yCAA0B;AAAA,QAC/C,GAAG;AAAA,QACH,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,kBAAkB,IAAK,MAAM,SAAS,KAAK;AAC1D,cAAM,IAAI,yBAAY,SAAS,QAAQ,OAAO,iBAAiB;AAAA,MACjE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,aAAa,GAAG;AAClC,gCAAAA,SAAU,cAAc,0BAA0B;AAClD,gCAAAA,SAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,aAAa,SAAS,cAAc;AAC1C,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AAEtF,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,iBAAW,QAAQ,CAAC,UAAU,IAAI,aAAa,OAAO,eAAe,KAAK,CAAC;AAE3E,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,IAAK,MAAM,SAAS,KAAK;AACxC,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,UACT;AAAA,UACA,iCAAiC,OAAO,GAAG,CAAC,GAAG,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,QACzE;AAAA,MACF;AACA,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,KAAK,QAAQ,KAAK;AAAA,UAClB,MAAM,QAAQ,KAAK;AAAA,UACnB,SAAS,QAAQ,KAAK;AAAA,UACtB,OAAO,QAAQ,KAAK;AAAA,UACpB,gBAAgB,QAAQ,KAAK,YAAY;AAAA,UACzC,oBAAoB,QAAQ,KAAK;AAAA,UACjC,SAAS,iBAAiB,QAAQ,KAAK,QAAQ;AAAA,UAC/C,SAAS,QAAQ,KAAK;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,mBAAmB,QAAQ;AAC/B,iBAAO,kCAAmB,EAAE,GAAG,QAAQ,UAAU,KAAK,UAAU,gBAAgB,QAAQ,CAAC;AAAA,IAC3F;AAAA,IACA,MAAM,YAAY,QAAQ;AACxB,gCAAAA,SAAU,KAAK,gBAAgB,4BAA4B;AAC3D,iBAAO,2BAAY;AAAA,QACjB,GAAG;AAAA,QACH,gBAAgB,KAAK;AAAA,QACrB,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":["invariant"]}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
// src/oauth2/provider/x.ts
|
|
2
2
|
import invariant from "tiny-invariant";
|
|
3
|
-
import { fetch } from "undici";
|
|
4
3
|
import { OAuth2Error } from "../error.mjs";
|
|
5
4
|
import {
|
|
6
5
|
createAuthorizationUri,
|
|
7
6
|
exchangeAuthorizationCode,
|
|
8
|
-
proxyAgent,
|
|
9
7
|
refreshAccessToken,
|
|
10
8
|
revokeToken
|
|
11
9
|
} from "./common.mjs";
|
|
@@ -54,7 +52,7 @@ function x(options) {
|
|
|
54
52
|
const headers = { Accept: "application/json", Authorization: `Bearer ${access_token}` };
|
|
55
53
|
const url = new URL(this.userInfoUri);
|
|
56
54
|
userFields.forEach((field) => url.searchParams.append("user.fields", field));
|
|
57
|
-
const response = await fetch(this.userInfoUri, { headers
|
|
55
|
+
const response = await fetch(this.userInfoUri, { headers });
|
|
58
56
|
if (!response.ok) {
|
|
59
57
|
const { errors } = await response.json();
|
|
60
58
|
throw new OAuth2Error(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import invariant from 'tiny-invariant';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import invariant from 'tiny-invariant';\nimport { Provider } from '../types';\nimport { OAuth2Error } from '../error';\nimport {\n createAuthorizationUri,\n exchangeAuthorizationCode,\n refreshAccessToken,\n revokeToken,\n} from './common';\n\nexport interface XOptions {\n userFields?: UserField[];\n}\n\nconst defaultUserFields = [\n 'id',\n 'name',\n 'profile_image_url',\n 'url',\n 'username',\n 'location',\n 'verified',\n];\n\nexport function x(options?: XOptions): Provider<XUserInfo> {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRevokeUri: 'https://api.x.com/2/oauth2/revoke',\n // https://docs.x.com/x-api/users/user-lookup-me\n userInfoUri: 'https://api.x.com/2/users/me',\n defaultScope: ['users.read', 'tweet.read', 'offline.access'],\n createAuthorizationUri(params) {\n if (!params.codeVerifier) throw new Error('codeVerifier is required for x');\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode(params) {\n if (!params.codeVerifier) throw new Error('codeVerifier is required for x');\n const response = await exchangeAuthorizationCode({\n ...params,\n tokenUri: this.tokenUri,\n authentication: 'basic',\n });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as XErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as XOAuth2Token;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const userFields = options?.userFields ?? defaultUserFields;\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n\n const url = new URL(this.userInfoUri);\n userFields.forEach((field) => url.searchParams.append('user.fields', field));\n\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n const { errors } = (await response.json()) as XAPIErrorResponse;\n throw new OAuth2Error(\n response.status,\n 'invalid_request',\n 'Failed to fetch user info: ' + (errors.at(0)?.detail ?? errors.at(0)?.title)\n );\n }\n const profile = (await response.json()) as XUserInfo;\n return {\n data: profile,\n claims: {\n sub: profile.data.id,\n name: profile.data.name,\n picture: profile.data.profile_image_url,\n email: profile.data.email,\n email_verified: profile.data.verified || false,\n preferred_username: profile.data.username,\n profile: `https://x.com/${profile.data.username}`,\n website: profile.data.url,\n },\n };\n },\n async refreshAccessToken(params) {\n return refreshAccessToken({ ...params, tokenUri: this.tokenUri, authentication: 'basic' });\n },\n async revokeToken(params) {\n invariant(this.tokenRevokeUri, 'tokenRevokeUri is required');\n return revokeToken({\n ...params,\n tokenRevokeUri: this.tokenRevokeUri,\n authentication: 'basic',\n });\n },\n };\n}\n\ntype UserField =\n | 'affiliation'\n | 'connection_status'\n | 'created_at'\n | 'description'\n | 'entities'\n | 'id'\n | 'is_identity_verified'\n | 'location'\n | 'most_recent_tweet_id'\n | 'name'\n | 'parody'\n | 'pinned_tweet_id'\n | 'profile_banner_url'\n | 'profile_image_url'\n | 'protected'\n | 'public_metrics'\n | 'receives_your_dm'\n | 'subscription'\n | 'subscription_type'\n | 'url'\n | 'username'\n | 'verified'\n | 'verified_followers_count'\n | 'verified_type'\n | 'withheld';\n\nexport interface XUser {\n id: string;\n name: string;\n email?: string;\n username: string;\n location?: string;\n entities?: {\n url: { urls: UrlEntity[] };\n description: {\n hashtags: HashtagEntity[];\n cashtags: HashtagEntity[];\n mentions: MentionEntity[];\n };\n };\n verified?: boolean;\n description?: string;\n url?: string;\n profile_image_url?: string;\n protected?: boolean;\n pinned_tweet_id?: string;\n created_at?: string;\n}\n\nexport interface XUserInfo {\n data: XUser;\n includes?: { tweets?: { id: string; text: string }[]; users?: XUser[] };\n}\n\n// prettier-ignore\ntype UrlEntity = { start: number; end: number; url: string; display_url: string; expanded_url: string; }\ntype HashtagEntity = { start: number; end: number; tag: string };\ntype MentionEntity = { start: number; end: string; username: string };\n\ntype XOAuth2Token = {\n token_type: string;\n expires_in: number;\n access_token: string;\n scope: string;\n refresh_token: string;\n};\n\ntype XErrorResponse = { error: string; error_description: string };\ntype XAPIErrorResponse = {\n errors: { title: string; type: string; detail?: string; status?: number }[];\n};\n"],"mappings":";AAAA,OAAO,eAAe;AAEtB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,EAAE,SAAyC;AACzD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,gBAAgB;AAAA;AAAA,IAEhB,aAAa;AAAA,IACb,cAAc,CAAC,cAAc,cAAc,gBAAgB;AAAA,IAC3D,uBAAuB,QAAQ;AAC7B,UAAI,CAAC,OAAO,aAAc,OAAM,IAAI,MAAM,gCAAgC;AAC1E,aAAO,uBAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,QAAQ;AACtC,UAAI,CAAC,OAAO,aAAc,OAAM,IAAI,MAAM,gCAAgC;AAC1E,YAAM,WAAW,MAAM,0BAA0B;AAAA,QAC/C,GAAG;AAAA,QACH,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,kBAAkB,IAAK,MAAM,SAAS,KAAK;AAC1D,cAAM,IAAI,YAAY,SAAS,QAAQ,OAAO,iBAAiB;AAAA,MACjE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,aAAa,GAAG;AAClC,gBAAU,cAAc,0BAA0B;AAClD,gBAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,aAAa,SAAS,cAAc;AAC1C,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AAEtF,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,iBAAW,QAAQ,CAAC,UAAU,IAAI,aAAa,OAAO,eAAe,KAAK,CAAC;AAE3E,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,IAAK,MAAM,SAAS,KAAK;AACxC,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,UACT;AAAA,UACA,iCAAiC,OAAO,GAAG,CAAC,GAAG,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,QACzE;AAAA,MACF;AACA,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,KAAK,QAAQ,KAAK;AAAA,UAClB,MAAM,QAAQ,KAAK;AAAA,UACnB,SAAS,QAAQ,KAAK;AAAA,UACtB,OAAO,QAAQ,KAAK;AAAA,UACpB,gBAAgB,QAAQ,KAAK,YAAY;AAAA,UACzC,oBAAoB,QAAQ,KAAK;AAAA,UACjC,SAAS,iBAAiB,QAAQ,KAAK,QAAQ;AAAA,UAC/C,SAAS,QAAQ,KAAK;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,mBAAmB,QAAQ;AAC/B,aAAO,mBAAmB,EAAE,GAAG,QAAQ,UAAU,KAAK,UAAU,gBAAgB,QAAQ,CAAC;AAAA,IAC3F;AAAA,IACA,MAAM,YAAY,QAAQ;AACxB,gBAAU,KAAK,gBAAgB,4BAA4B;AAC3D,aAAO,YAAY;AAAA,QACjB,GAAG;AAAA,QACH,gBAAgB,KAAK;AAAA,QACrB,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shware/security",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"jsonwebtoken": "^9.0.2",
|
|
39
39
|
"path-to-regexp": "^8.2.0",
|
|
40
40
|
"tiny-invariant": "^1.3.3",
|
|
41
|
-
"undici": "^7.5.0",
|
|
42
41
|
"zod": "^3.24.2"
|
|
43
42
|
}
|
|
44
43
|
}
|