@shware/security 2.0.0 → 2.0.2
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/auth/index.cjs +18 -7
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.mjs +25 -8
- package/dist/auth/index.mjs.map +1 -1
- package/dist/oauth2/client.cjs.map +1 -1
- package/dist/oauth2/client.mjs.map +1 -1
- package/dist/oauth2/provider/apple.cjs.map +1 -1
- package/dist/oauth2/provider/apple.mjs.map +1 -1
- package/dist/oauth2/provider/common.cjs.map +1 -1
- package/dist/oauth2/provider/common.mjs.map +1 -1
- package/dist/oauth2/provider/facebook.cjs.map +1 -1
- package/dist/oauth2/provider/facebook.mjs.map +1 -1
- package/dist/oauth2/provider/github.cjs.map +1 -1
- package/dist/oauth2/provider/github.mjs.map +1 -1
- package/dist/oauth2/provider/google.cjs.map +1 -1
- package/dist/oauth2/provider/google.mjs.map +1 -1
- package/dist/oauth2/provider/wechat.cjs +1 -1
- package/dist/oauth2/provider/wechat.cjs.map +1 -1
- package/dist/oauth2/provider/wechat.mjs +1 -1
- package/dist/oauth2/provider/wechat.mjs.map +1 -1
- package/dist/oauth2/provider/x.cjs +1 -1
- package/dist/oauth2/provider/x.cjs.map +1 -1
- package/dist/oauth2/provider/x.mjs +1 -1
- package/dist/oauth2/provider/x.mjs.map +1 -1
- package/dist/session/__tests__/redis.test.cjs +3119 -17
- package/dist/session/__tests__/redis.test.cjs.map +1 -1
- package/dist/session/__tests__/redis.test.mjs +3148 -17
- package/dist/session/__tests__/redis.test.mjs.map +1 -1
- package/dist/session/map-session.cjs.map +1 -1
- package/dist/session/map-session.mjs.map +1 -1
- package/dist/session/redis.cjs.map +1 -1
- package/dist/session/redis.mjs.map +1 -1
- package/package.json +16 -19
- package/dist/session/workers-kv.cjs +0 -2
- package/dist/session/workers-kv.cjs.map +0 -1
- package/dist/session/workers-kv.d.cts +0 -2
- package/dist/session/workers-kv.d.ts +0 -2
- package/dist/session/workers-kv.mjs +0 -1
- package/dist/session/workers-kv.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\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.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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.pkce) body.append('code_verifier', params.pkce.code_verifier);\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\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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 return fetch(params.tokenUri, { method: 'POST', headers, body });\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\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks);\n return payload as T;\n } catch {\n console.error('Failed to verify id_token');\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\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.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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.pkce) body.append('code_verifier', params.pkce.code_verifier);\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\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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 return fetch(params.tokenUri, { method: 'POST', headers, body });\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\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks);\n return payload as T;\n } catch {\n console.error('Failed to verify id_token');\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\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.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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.pkce) body.append('code_verifier', params.pkce.code_verifier);\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\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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 return fetch(params.tokenUri, { method: 'POST', headers, body });\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\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks);\n return payload as T;\n } catch {\n console.error('Failed to verify id_token');\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\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.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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.pkce) body.append('code_verifier', params.pkce.code_verifier);\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\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\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 return fetch(params.tokenUri, { method: 'POST', headers, body });\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\nexport async function verifyIdToken<T>(idToken: string, jwkSetUri: string) {\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks);\n return payload as T;\n } catch {\n console.error('Failed to verify id_token');\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { LoginOAuth2NativeParams, OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: true,\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const url = new URL(this.userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', access_token);\n url.searchParams.append('fields', fields.join(','));\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n email_verified: data.email_verified,\n },\n };\n },\n async loginOAuth2Native({ credentials }: LoginOAuth2NativeParams) {\n if (credentials.id_token || credentials.access_token) {\n const userInfo = await this.getUserInfo(credentials as unknown as OAuth2Token);\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: credentials.access_token ?? '',\n id_token: credentials.id_token,\n };\n return { token, userInfo };\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n email_verified: boolean;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0B;AAC1B,mBAA4B;AAE5B,oBAAiF;AAM1E,SAAS,yBAAmC;AACjD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,cAAc,CAAC,WAAW,OAAO;AAAA,IACjC,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,iBAAO,sCAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,UAAM,yCAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,MAAM,IAAK,MAAM,SAAS,KAAK;AACvC,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,MAAM,OAAO;AAAA,MACzE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,UAAU,aAAa,GAAG;AAC5C,kCAAU,KAAK,WAAW,uBAAuB;AACjD,UAAI,UAAU;AACZ,cAAMA,QAAO,UAAM,6BAAsC,UAAU,KAAK,SAAS;AACjF,eAAO;AAAA,UACL,MAAAA;AAAA,UACA,QAAQ;AAAA,YACN,KAAKA,MAAK;AAAA,YACV,MAAMA,MAAK;AAAA,YACX,SAASA,MAAK;AAAA,YACd,OAAOA,MAAK;AAAA,YACZ,gBAAgB;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AACA,kCAAU,cAAc,0BAA0B;AAClD,kCAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,YAAM,SAAS,CAAC,MAAM,QAAQ,SAAS,gCAAgC;AACvE,UAAI,aAAa,OAAO,gBAAgB,YAAY;AACpD,UAAI,aAAa,OAAO,UAAU,OAAO,KAAK,GAAG,CAAC;AAClD,YAAM,UAAU,EAAE,QAAQ,mBAAmB;AAC7C,YAAM,WAAW,MAAM,MAAM,IAAI,MAAM,EAAE,QAAQ,CAAC;AAClD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK,QAAQ,KAAK;AAAA,UAC3B,gBAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,YAAY,GAA4B;AAChE,UAAI,YAAY,YAAY,YAAY,cAAc;AACpD,cAAM,WAAW,MAAM,KAAK,YAAY,WAAqC;AAC7E,cAAM,QAAqB;AAAA,UACzB,YAAY;AAAA,UACZ,cAAc,YAAY,gBAAgB;AAAA,UAC1C,UAAU,YAAY;AAAA,QACxB;AACA,eAAO,EAAE,OAAO,SAAS;AAAA,MAC3B,OAAO;AACL,cAAM,IAAI,yBAAY,KAAK,mBAAmB,sCAAsC;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,WAAW,uBAAuB;","names":["data"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { LoginOAuth2NativeParams, OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: true,\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const url = new URL(this.userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', access_token);\n url.searchParams.append('fields', fields.join(','));\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n email_verified: data.email_verified,\n },\n };\n },\n async loginOAuth2Native({ credentials }: LoginOAuth2NativeParams) {\n if (credentials.id_token || credentials.access_token) {\n const userInfo = await this.getUserInfo(credentials as unknown as OAuth2Token);\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: credentials.access_token ?? '',\n id_token: credentials.id_token,\n };\n return { token, userInfo };\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n email_verified: boolean;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0B;AAC1B,mBAA4B;AAE5B,oBAAiF;AAM1E,SAAS,yBAAmC;AACjD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,cAAc,CAAC,WAAW,OAAO;AAAA,IACjC,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,iBAAO,sCAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,UAAM,yCAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,MAAM,IAAK,MAAM,SAAS,KAAK;AACvC,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,MAAM,OAAO;AAAA,MACzE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,UAAU,aAAa,GAAG;AAC5C,kCAAU,KAAK,WAAW,uBAAuB;AACjD,UAAI,UAAU;AACZ,cAAMA,QAAO,UAAM,6BAAsC,UAAU,KAAK,SAAS;AACjF,eAAO;AAAA,UACL,MAAAA;AAAA,UACA,QAAQ;AAAA,YACN,KAAKA,MAAK;AAAA,YACV,MAAMA,MAAK;AAAA,YACX,SAASA,MAAK;AAAA,YACd,OAAOA,MAAK;AAAA,YACZ,gBAAgB;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AACA,kCAAU,cAAc,0BAA0B;AAClD,kCAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,YAAM,SAAS,CAAC,MAAM,QAAQ,SAAS,gCAAgC;AACvE,UAAI,aAAa,OAAO,gBAAgB,YAAY;AACpD,UAAI,aAAa,OAAO,UAAU,OAAO,KAAK,GAAG,CAAC;AAClD,YAAM,UAAU,EAAE,QAAQ,mBAAmB;AAC7C,YAAM,WAAW,MAAM,MAAM,IAAI,MAAM,EAAE,QAAQ,CAAC;AAClD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK,QAAQ,KAAK;AAAA,UAC3B,gBAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,YAAY,GAA4B;AAChE,UAAI,YAAY,YAAY,YAAY,cAAc;AACpD,cAAM,WAAW,MAAM,KAAK,YAAY,WAAqC;AAC7E,cAAM,QAAqB;AAAA,UACzB,YAAY;AAAA,UACZ,cAAc,YAAY,gBAAgB;AAAA,UAC1C,UAAU,YAAY;AAAA,QACxB;AACA,eAAO,EAAE,OAAO,SAAS;AAAA,MAC3B,OAAO;AACL,cAAM,IAAI,yBAAY,KAAK,mBAAmB,sCAAsC;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,WAAW,uBAAuB;","names":["data"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { LoginOAuth2NativeParams, OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: true,\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const url = new URL(this.userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', access_token);\n url.searchParams.append('fields', fields.join(','));\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n email_verified: data.email_verified,\n },\n };\n },\n async loginOAuth2Native({ credentials }: LoginOAuth2NativeParams) {\n if (credentials.id_token || credentials.access_token) {\n const userInfo = await this.getUserInfo(credentials as unknown as OAuth2Token);\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: credentials.access_token ?? '',\n id_token: credentials.id_token,\n };\n return { token, userInfo };\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n email_verified: boolean;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB,2BAA2B,qBAAqB;AAM1E,SAAS,yBAAmC;AACjD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,cAAc,CAAC,WAAW,OAAO;AAAA,IACjC,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,aAAO,uBAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,MAAM,0BAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,MAAM,IAAK,MAAM,SAAS,KAAK;AACvC,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,MAAM,OAAO;AAAA,MACzE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,UAAU,aAAa,GAAG;AAC5C,gBAAU,KAAK,WAAW,uBAAuB;AACjD,UAAI,UAAU;AACZ,cAAMA,QAAO,MAAM,cAAsC,UAAU,KAAK,SAAS;AACjF,eAAO;AAAA,UACL,MAAAA;AAAA,UACA,QAAQ;AAAA,YACN,KAAKA,MAAK;AAAA,YACV,MAAMA,MAAK;AAAA,YACX,SAASA,MAAK;AAAA,YACd,OAAOA,MAAK;AAAA,YACZ,gBAAgB;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AACA,gBAAU,cAAc,0BAA0B;AAClD,gBAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,YAAM,SAAS,CAAC,MAAM,QAAQ,SAAS,gCAAgC;AACvE,UAAI,aAAa,OAAO,gBAAgB,YAAY;AACpD,UAAI,aAAa,OAAO,UAAU,OAAO,KAAK,GAAG,CAAC;AAClD,YAAM,UAAU,EAAE,QAAQ,mBAAmB;AAC7C,YAAM,WAAW,MAAM,MAAM,IAAI,MAAM,EAAE,QAAQ,CAAC;AAClD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK,QAAQ,KAAK;AAAA,UAC3B,gBAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,YAAY,GAA4B;AAChE,UAAI,YAAY,YAAY,YAAY,cAAc;AACpD,cAAM,WAAW,MAAM,KAAK,YAAY,WAAqC;AAC7E,cAAM,QAAqB;AAAA,UACzB,YAAY;AAAA,UACZ,cAAc,YAAY,gBAAgB;AAAA,UAC1C,UAAU,YAAY;AAAA,QACxB;AACA,eAAO,EAAE,OAAO,SAAS;AAAA,MAC3B,OAAO;AACL,cAAM,IAAI,YAAY,KAAK,mBAAmB,sCAAsC;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,WAAW,uBAAuB;","names":["data"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { LoginOAuth2NativeParams, OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: true,\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n\n const url = new URL(this.userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', access_token);\n url.searchParams.append('fields', fields.join(','));\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n email_verified: data.email_verified,\n },\n };\n },\n async loginOAuth2Native({ credentials }: LoginOAuth2NativeParams) {\n if (credentials.id_token || credentials.access_token) {\n const userInfo = await this.getUserInfo(credentials as unknown as OAuth2Token);\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: credentials.access_token ?? '',\n id_token: credentials.id_token,\n };\n return { token, userInfo };\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n email_verified: boolean;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB,2BAA2B,qBAAqB;AAM1E,SAAS,yBAAmC;AACjD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,cAAc,CAAC,WAAW,OAAO;AAAA,IACjC,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,aAAO,uBAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,MAAM,0BAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,MAAM,IAAK,MAAM,SAAS,KAAK;AACvC,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,MAAM,OAAO;AAAA,MACzE;AACA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,EAAE,UAAU,aAAa,GAAG;AAC5C,gBAAU,KAAK,WAAW,uBAAuB;AACjD,UAAI,UAAU;AACZ,cAAMA,QAAO,MAAM,cAAsC,UAAU,KAAK,SAAS;AACjF,eAAO;AAAA,UACL,MAAAA;AAAA,UACA,QAAQ;AAAA,YACN,KAAKA,MAAK;AAAA,YACV,MAAMA,MAAK;AAAA,YACX,SAASA,MAAK;AAAA,YACd,OAAOA,MAAK;AAAA,YACZ,gBAAgB;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AACA,gBAAU,cAAc,0BAA0B;AAClD,gBAAU,KAAK,aAAa,yBAAyB;AAErD,YAAM,MAAM,IAAI,IAAI,KAAK,WAAW;AACpC,YAAM,SAAS,CAAC,MAAM,QAAQ,SAAS,gCAAgC;AACvE,UAAI,aAAa,OAAO,gBAAgB,YAAY;AACpD,UAAI,aAAa,OAAO,UAAU,OAAO,KAAK,GAAG,CAAC;AAClD,YAAM,UAAU,EAAE,QAAQ,mBAAmB;AAC7C,YAAM,WAAW,MAAM,MAAM,IAAI,MAAM,EAAE,QAAQ,CAAC;AAClD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK,QAAQ,KAAK;AAAA,UAC3B,gBAAgB,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,YAAY,GAA4B;AAChE,UAAI,YAAY,YAAY,YAAY,cAAc;AACpD,cAAM,WAAW,MAAM,KAAK,YAAY,WAAqC;AAC7E,cAAM,QAAqB;AAAA,UACzB,YAAY;AAAA,UACZ,cAAc,YAAY,gBAAgB;AAAA,UAC1C,UAAU,YAAY;AAAA,QACxB;AACA,eAAO,EAAE,OAAO,SAAS;AAAA,MAC3B,OAAO;AACL,cAAM,IAAI,YAAY,KAAK,mBAAmB,sCAAsC;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,WAAW,uBAAuB;","names":["data"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/github.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode } from './common';\n\nexport function createGithubProvider(): Provider {\n return {\n authorizationUri: 'https://github.com/login/oauth/authorize',\n tokenUri: 'https://github.com/login/oauth/access_token',\n userInfoUri: 'https://api.github.com/user',\n userNameAttribute: 'id',\n defaultScope: ['user:email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GithubErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GithubToken;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as GithubUserInfo;\n const emailResponse = await fetch('https://api.github.com/user/emails', { headers });\n if (!emailResponse.ok) {\n throw new OAuth2Error(\n emailResponse.status,\n 'invalid_request',\n 'Failed to fetch user email'\n );\n }\n const emails = (await emailResponse.json()) as GithubEmail[];\n data.email = emails.find((email) => email.primary)?.email || data.email;\n const email_verified = emails.find((email) => email.email === data.email)?.verified || false;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name || data.login,\n email_verified,\n email: data.email,\n picture: data.avatar_url,\n profile: data.html_url,\n website: data.html_url,\n updated_at: data.updated_at ? Date.parse(data.updated_at) : undefined,\n },\n };\n },\n };\n}\n\nexport const github = createGithubProvider();\n\nexport interface GithubUserInfo {\n login: string;\n id: string;\n node_id: string;\n avatar_url: string;\n gravatar_id: string;\n url: string;\n html_url: string;\n followers_url: string;\n following_url: string;\n gists_url: string;\n starred_url: string;\n subscriptions_url: string;\n organizations_url: string;\n repos_url: string;\n events_url: string;\n received_events_url: string;\n type: string;\n site_admin: boolean;\n name: string;\n company: string;\n blog: string;\n location: string;\n email: string;\n hireable: boolean;\n bio: string;\n twitter_username: string;\n public_repos: string;\n public_gists: string;\n followers: string;\n following: string;\n created_at: string;\n updated_at: string;\n private_gists: string;\n total_private_repos: string;\n owned_private_repos: string;\n disk_usage: string;\n collaborators: string;\n two_factor_authentication: boolean;\n plan: {\n name: string;\n space: string;\n private_repos: string;\n collaborators: string;\n };\n}\n\ninterface GithubEmail {\n email: string;\n primary: boolean;\n verified: boolean;\n visibility: 'public' | 'private';\n}\n\nexport interface GithubToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n scope: string;\n expires_in: number;\n refresh_token: string;\n}\n\ninterface GithubErrorResponse {\n error: string;\n error_description: string;\n error_uri: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0B;AAC1B,mBAA4B;AAE5B,oBAAkE;AAE3D,SAAS,uBAAiC;AAC/C,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc,CAAC,YAAY;AAAA,IAC3B,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,iBAAO,sCAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,UAAM,yCAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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,kCAAU,cAAc,0BAA0B;AAClD,kCAAU,KAAK,aAAa,yBAAyB;AACrD,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AACtF,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,gBAAgB,MAAM,MAAM,sCAAsC,EAAE,QAAQ,CAAC;AACnF,UAAI,CAAC,cAAc,IAAI;AACrB,cAAM,IAAI;AAAA,UACR,cAAc;AAAA,UACd;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,SAAU,MAAM,cAAc,KAAK;AACzC,WAAK,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,SAAS,KAAK;AAClE,YAAM,iBAAiB,OAAO,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK,KAAK,GAAG,YAAY;AACvF,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK,QAAQ,KAAK;AAAA,UACxB;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,YAAY,KAAK,aAAa,KAAK,MAAM,KAAK,UAAU,IAAI;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/github.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode } from './common';\n\nexport function createGithubProvider(): Provider {\n return {\n authorizationUri: 'https://github.com/login/oauth/authorize',\n tokenUri: 'https://github.com/login/oauth/access_token',\n userInfoUri: 'https://api.github.com/user',\n userNameAttribute: 'id',\n defaultScope: ['user:email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GithubErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GithubToken;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as GithubUserInfo;\n const emailResponse = await fetch('https://api.github.com/user/emails', { headers });\n if (!emailResponse.ok) {\n throw new OAuth2Error(\n emailResponse.status,\n 'invalid_request',\n 'Failed to fetch user email'\n );\n }\n const emails = (await emailResponse.json()) as GithubEmail[];\n data.email = emails.find((email) => email.primary)?.email || data.email;\n const email_verified = emails.find((email) => email.email === data.email)?.verified || false;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name || data.login,\n email_verified,\n email: data.email,\n picture: data.avatar_url,\n profile: data.html_url,\n website: data.html_url,\n updated_at: data.updated_at ? Date.parse(data.updated_at) : undefined,\n },\n };\n },\n };\n}\n\nexport const github = createGithubProvider();\n\nexport interface GithubUserInfo {\n login: string;\n id: string;\n node_id: string;\n avatar_url: string;\n gravatar_id: string;\n url: string;\n html_url: string;\n followers_url: string;\n following_url: string;\n gists_url: string;\n starred_url: string;\n subscriptions_url: string;\n organizations_url: string;\n repos_url: string;\n events_url: string;\n received_events_url: string;\n type: string;\n site_admin: boolean;\n name: string;\n company: string;\n blog: string;\n location: string;\n email: string;\n hireable: boolean;\n bio: string;\n twitter_username: string;\n public_repos: string;\n public_gists: string;\n followers: string;\n following: string;\n created_at: string;\n updated_at: string;\n private_gists: string;\n total_private_repos: string;\n owned_private_repos: string;\n disk_usage: string;\n collaborators: string;\n two_factor_authentication: boolean;\n plan: {\n name: string;\n space: string;\n private_repos: string;\n collaborators: string;\n };\n}\n\ninterface GithubEmail {\n email: string;\n primary: boolean;\n verified: boolean;\n visibility: 'public' | 'private';\n}\n\nexport interface GithubToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n scope: string;\n expires_in: number;\n refresh_token: string;\n}\n\ninterface GithubErrorResponse {\n error: string;\n error_description: string;\n error_uri: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0B;AAC1B,mBAA4B;AAE5B,oBAAkE;AAE3D,SAAS,uBAAiC;AAC/C,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc,CAAC,YAAY;AAAA,IAC3B,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,iBAAO,sCAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,UAAM,yCAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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,kCAAU,cAAc,0BAA0B;AAClD,kCAAU,KAAK,aAAa,yBAAyB;AACrD,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AACtF,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,yBAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,gBAAgB,MAAM,MAAM,sCAAsC,EAAE,QAAQ,CAAC;AACnF,UAAI,CAAC,cAAc,IAAI;AACrB,cAAM,IAAI;AAAA,UACR,cAAc;AAAA,UACd;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,SAAU,MAAM,cAAc,KAAK;AACzC,WAAK,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,SAAS,KAAK;AAClE,YAAM,iBAAiB,OAAO,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK,KAAK,GAAG,YAAY;AACvF,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK,QAAQ,KAAK;AAAA,UACxB;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,YAAY,KAAK,aAAa,KAAK,MAAM,KAAK,UAAU,IAAI;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/github.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode } from './common';\n\nexport function createGithubProvider(): Provider {\n return {\n authorizationUri: 'https://github.com/login/oauth/authorize',\n tokenUri: 'https://github.com/login/oauth/access_token',\n userInfoUri: 'https://api.github.com/user',\n userNameAttribute: 'id',\n defaultScope: ['user:email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GithubErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GithubToken;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as GithubUserInfo;\n const emailResponse = await fetch('https://api.github.com/user/emails', { headers });\n if (!emailResponse.ok) {\n throw new OAuth2Error(\n emailResponse.status,\n 'invalid_request',\n 'Failed to fetch user email'\n );\n }\n const emails = (await emailResponse.json()) as GithubEmail[];\n data.email = emails.find((email) => email.primary)?.email || data.email;\n const email_verified = emails.find((email) => email.email === data.email)?.verified || false;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name || data.login,\n email_verified,\n email: data.email,\n picture: data.avatar_url,\n profile: data.html_url,\n website: data.html_url,\n updated_at: data.updated_at ? Date.parse(data.updated_at) : undefined,\n },\n };\n },\n };\n}\n\nexport const github = createGithubProvider();\n\nexport interface GithubUserInfo {\n login: string;\n id: string;\n node_id: string;\n avatar_url: string;\n gravatar_id: string;\n url: string;\n html_url: string;\n followers_url: string;\n following_url: string;\n gists_url: string;\n starred_url: string;\n subscriptions_url: string;\n organizations_url: string;\n repos_url: string;\n events_url: string;\n received_events_url: string;\n type: string;\n site_admin: boolean;\n name: string;\n company: string;\n blog: string;\n location: string;\n email: string;\n hireable: boolean;\n bio: string;\n twitter_username: string;\n public_repos: string;\n public_gists: string;\n followers: string;\n following: string;\n created_at: string;\n updated_at: string;\n private_gists: string;\n total_private_repos: string;\n owned_private_repos: string;\n disk_usage: string;\n collaborators: string;\n two_factor_authentication: boolean;\n plan: {\n name: string;\n space: string;\n private_repos: string;\n collaborators: string;\n };\n}\n\ninterface GithubEmail {\n email: string;\n primary: boolean;\n verified: boolean;\n visibility: 'public' | 'private';\n}\n\nexport interface GithubToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n scope: string;\n expires_in: number;\n refresh_token: string;\n}\n\ninterface GithubErrorResponse {\n error: string;\n error_description: string;\n error_uri: string;\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB,iCAAiC;AAE3D,SAAS,uBAAiC;AAC/C,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc,CAAC,YAAY;AAAA,IAC3B,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,aAAO,uBAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,MAAM,0BAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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;AACrD,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AACtF,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,gBAAgB,MAAM,MAAM,sCAAsC,EAAE,QAAQ,CAAC;AACnF,UAAI,CAAC,cAAc,IAAI;AACrB,cAAM,IAAI;AAAA,UACR,cAAc;AAAA,UACd;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,SAAU,MAAM,cAAc,KAAK;AACzC,WAAK,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,SAAS,KAAK;AAClE,YAAM,iBAAiB,OAAO,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK,KAAK,GAAG,YAAY;AACvF,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK,QAAQ,KAAK;AAAA,UACxB;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,YAAY,KAAK,aAAa,KAAK,MAAM,KAAK,UAAU,IAAI;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/github.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode } from './common';\n\nexport function createGithubProvider(): Provider {\n return {\n authorizationUri: 'https://github.com/login/oauth/authorize',\n tokenUri: 'https://github.com/login/oauth/access_token',\n userInfoUri: 'https://api.github.com/user',\n userNameAttribute: 'id',\n defaultScope: ['user:email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GithubErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GithubToken;\n },\n async getUserInfo({ access_token }) {\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n const headers = { Accept: 'application/json', Authorization: `Bearer ${access_token}` };\n const response = await fetch(this.userInfoUri, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as GithubUserInfo;\n const emailResponse = await fetch('https://api.github.com/user/emails', { headers });\n if (!emailResponse.ok) {\n throw new OAuth2Error(\n emailResponse.status,\n 'invalid_request',\n 'Failed to fetch user email'\n );\n }\n const emails = (await emailResponse.json()) as GithubEmail[];\n data.email = emails.find((email) => email.primary)?.email || data.email;\n const email_verified = emails.find((email) => email.email === data.email)?.verified || false;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name || data.login,\n email_verified,\n email: data.email,\n picture: data.avatar_url,\n profile: data.html_url,\n website: data.html_url,\n updated_at: data.updated_at ? Date.parse(data.updated_at) : undefined,\n },\n };\n },\n };\n}\n\nexport const github = createGithubProvider();\n\nexport interface GithubUserInfo {\n login: string;\n id: string;\n node_id: string;\n avatar_url: string;\n gravatar_id: string;\n url: string;\n html_url: string;\n followers_url: string;\n following_url: string;\n gists_url: string;\n starred_url: string;\n subscriptions_url: string;\n organizations_url: string;\n repos_url: string;\n events_url: string;\n received_events_url: string;\n type: string;\n site_admin: boolean;\n name: string;\n company: string;\n blog: string;\n location: string;\n email: string;\n hireable: boolean;\n bio: string;\n twitter_username: string;\n public_repos: string;\n public_gists: string;\n followers: string;\n following: string;\n created_at: string;\n updated_at: string;\n private_gists: string;\n total_private_repos: string;\n owned_private_repos: string;\n disk_usage: string;\n collaborators: string;\n two_factor_authentication: boolean;\n plan: {\n name: string;\n space: string;\n private_repos: string;\n collaborators: string;\n };\n}\n\ninterface GithubEmail {\n email: string;\n primary: boolean;\n verified: boolean;\n visibility: 'public' | 'private';\n}\n\nexport interface GithubToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n scope: string;\n expires_in: number;\n refresh_token: string;\n}\n\ninterface GithubErrorResponse {\n error: string;\n error_description: string;\n error_uri: string;\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB,iCAAiC;AAE3D,SAAS,uBAAiC;AAC/C,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc,CAAC,YAAY;AAAA,IAC3B,uBAAuB,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AAC7C,aAAO,uBAAuB;AAAA,QAC5B,GAAG;AAAA,QACH,OAAO,OAAO,SAAS,KAAK;AAAA,QAC5B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,MAAM,0BAA0B,EAAE,MAAM,GAAG,GAAG,OAAO,GAAG;AACtD,YAAM,WAAW,MAAM,0BAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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;AACrD,YAAM,UAAU,EAAE,QAAQ,oBAAoB,eAAe,UAAU,YAAY,GAAG;AACtF,YAAM,WAAW,MAAM,MAAM,KAAK,aAAa,EAAE,QAAQ,CAAC;AAC1D,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY,SAAS,QAAQ,mBAAmB,2BAA2B;AAAA,MACvF;AACA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,gBAAgB,MAAM,MAAM,sCAAsC,EAAE,QAAQ,CAAC;AACnF,UAAI,CAAC,cAAc,IAAI;AACrB,cAAM,IAAI;AAAA,UACR,cAAc;AAAA,UACd;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,SAAU,MAAM,cAAc,KAAK;AACzC,WAAK,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,SAAS,KAAK;AAClE,YAAM,iBAAiB,OAAO,KAAK,CAAC,UAAU,MAAM,UAAU,KAAK,KAAK,GAAG,YAAY;AACvF,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK,QAAQ,KAAK;AAAA,UACxB;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,YAAY,KAAK,aAAa,KAAK,MAAM,KAAK,UAAU,IAAI;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/google.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/google.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type {\n LoginOAuth2NativeParams,\n NativeCredential,\n OAuth2Token,\n OneTapProvider,\n} from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\nexport function createGoogleProvider(): OneTapProvider {\n return {\n authorizationUri: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUri: 'https://oauth2.googleapis.com/token',\n userInfoUri: 'https://www.googleapis.com/oauth2/v3/userinfo',\n userNameAttribute: 'sub',\n jwkSetUri: 'https://www.googleapis.com/oauth2/v3/certs',\n // https://developers.google.com/identity/protocols/oauth2/scopes#oauth2\n defaultScope: [\n 'https://www.googleapis.com/auth/userinfo.email',\n 'https://www.googleapis.com/auth/userinfo.profile',\n 'openid',\n ],\n createAuthorizationUri(params) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode(params) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GoogleErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GoogleToken;\n },\n async getUserInfo({ id_token }) {\n invariant(id_token, 'id_token is required');\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n const data = await verifyIdToken<GoogleUserInfo>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: data.email_verified,\n given_name: data.given_name,\n family_name: data.family_name,\n locale: data.locale,\n },\n };\n },\n async loginOAuth2Native({ pkce: _, credentials, ...params }: LoginOAuth2NativeParams) {\n invariant(credentials.code, 'code is required');\n const { code } = credentials;\n const { tokenUri } = this;\n const response = await exchangeAuthorizationCode({ code, tokenUri, ...params });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GoogleErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n const token = (await response.json()) as GoogleToken;\n const userInfo = await this.getUserInfo(token);\n return { token, userInfo };\n },\n async getTokenInfo(id_token: string) {\n invariant(id_token, 'id_token is required');\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n const data = await verifyIdToken<GoogleUserInfo>(id_token, this.jwkSetUri);\n return {\n token: {\n id_token,\n access_token: '',\n token_type: '',\n expires_in: 0,\n refresh_token: '',\n scope: '',\n },\n userInfo: {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: data.email_verified,\n given_name: data.given_name,\n family_name: data.family_name,\n locale: data.locale,\n },\n },\n };\n },\n };\n}\n\nexport const google = createGoogleProvider();\n\nexport interface GoogleUserInfo {\n aud: string;\n azp: string;\n email: string;\n email_verified: boolean;\n exp: number;\n family_name: string;\n given_name: string;\n hd?: string;\n iat: number;\n iss: string;\n jti?: string;\n locale?: string;\n name: string;\n nbf?: number;\n picture: string;\n sub: string;\n nonce?: string;\n}\n\nexport interface GoogleToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n id_token: string;\n scope: string;\n}\n\n// android,ios has different client_id and redirect_uri\nexport interface GoogleAppCredential extends NativeCredential {\n state: string;\n code: string;\n client_id: string;\n redirect_uri: string;\n}\n\nexport interface GoogleErrorResponse {\n error:\n | 'invalid_request'\n | 'invalid_client'\n | 'invalid_grant'\n | 'invalid_token'\n | 'invalid_scope'\n | 'unauthorized_client'\n | 'unsupported_grant_type'\n | 'access_denied'\n | 'server_error';\n error_description: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0B;AAC1B,mBAA4B;AAO5B,oBAAiF;AAE1E,SAAS,uBAAuC;AACrD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,WAAW;AAAA;AAAA,IAEX,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,uBAAuB,QAAQ;AAC7B,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,YAAM,WAAW,UAAM,yCAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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,SAAS,GAAG;AAC9B,kCAAU,UAAU,sBAAsB;AAC1C,kCAAU,KAAK,WAAW,uBAAuB;AACjD,YAAM,OAAO,UAAM,6BAA8B,UAAU,KAAK,SAAS;AACzE,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,SAAS,KAAK;AAAA,UACd,OAAO,KAAK;AAAA,UACZ,gBAAgB,KAAK;AAAA,UACrB,YAAY,KAAK;AAAA,UACjB,aAAa,KAAK;AAAA,UAClB,QAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,GAA4B;AACpF,kCAAU,YAAY,MAAM,kBAAkB;AAC9C,YAAM,EAAE,KAAK,IAAI;AACjB,YAAM,EAAE,SAAS,IAAI;AACrB,YAAM,WAAW,UAAM,yCAA0B,EAAE,MAAM,UAAU,GAAG,OAAO,CAAC;AAC9E,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,kBAAkB,IAAK,MAAM,SAAS,KAAK;AAC1D,cAAM,IAAI,yBAAY,SAAS,QAAQ,OAAO,iBAAiB;AAAA,MACjE;AACA,YAAM,QAAS,MAAM,SAAS,KAAK;AACnC,YAAM,WAAW,MAAM,KAAK,YAAY,KAAK;AAC7C,aAAO,EAAE,OAAO,SAAS;AAAA,IAC3B;AAAA,IACA,MAAM,aAAa,UAAkB;AACnC,kCAAU,UAAU,sBAAsB;AAC1C,kCAAU,KAAK,WAAW,uBAAuB;AACjD,YAAM,OAAO,UAAM,6BAA8B,UAAU,KAAK,SAAS;AACzE,aAAO;AAAA,QACL,OAAO;AAAA,UACL;AAAA,UACA,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,eAAe;AAAA,UACf,OAAO;AAAA,QACT;AAAA,QACA,UAAU;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,YACN,KAAK,KAAK;AAAA,YACV,MAAM,KAAK;AAAA,YACX,SAAS,KAAK;AAAA,YACd,OAAO,KAAK;AAAA,YACZ,gBAAgB,KAAK;AAAA,YACrB,YAAY,KAAK;AAAA,YACjB,aAAa,KAAK;AAAA,YAClB,QAAQ,KAAK;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/google.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/google.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type {\n LoginOAuth2NativeParams,\n NativeCredential,\n OAuth2Token,\n OneTapProvider,\n} from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\nexport function createGoogleProvider(): OneTapProvider {\n return {\n authorizationUri: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUri: 'https://oauth2.googleapis.com/token',\n userInfoUri: 'https://www.googleapis.com/oauth2/v3/userinfo',\n userNameAttribute: 'sub',\n jwkSetUri: 'https://www.googleapis.com/oauth2/v3/certs',\n // https://developers.google.com/identity/protocols/oauth2/scopes#oauth2\n defaultScope: [\n 'https://www.googleapis.com/auth/userinfo.email',\n 'https://www.googleapis.com/auth/userinfo.profile',\n 'openid',\n ],\n createAuthorizationUri(params) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode(params) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GoogleErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n return (await response.json()) as GoogleToken;\n },\n async getUserInfo({ id_token }) {\n invariant(id_token, 'id_token is required');\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n const data = await verifyIdToken<GoogleUserInfo>(id_token, this.jwkSetUri);\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: data.email_verified,\n given_name: data.given_name,\n family_name: data.family_name,\n locale: data.locale,\n },\n };\n },\n async loginOAuth2Native({ pkce: _, credentials, ...params }: LoginOAuth2NativeParams) {\n invariant(credentials.code, 'code is required');\n const { code } = credentials;\n const { tokenUri } = this;\n const response = await exchangeAuthorizationCode({ code, tokenUri, ...params });\n if (!response.ok) {\n const { error, error_description } = (await response.json()) as GoogleErrorResponse;\n throw new OAuth2Error(response.status, error, error_description);\n }\n const token = (await response.json()) as GoogleToken;\n const userInfo = await this.getUserInfo(token);\n return { token, userInfo };\n },\n async getTokenInfo(id_token: string) {\n invariant(id_token, 'id_token is required');\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n const data = await verifyIdToken<GoogleUserInfo>(id_token, this.jwkSetUri);\n return {\n token: {\n id_token,\n access_token: '',\n token_type: '',\n expires_in: 0,\n refresh_token: '',\n scope: '',\n },\n userInfo: {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: data.email_verified,\n given_name: data.given_name,\n family_name: data.family_name,\n locale: data.locale,\n },\n },\n };\n },\n };\n}\n\nexport const google = createGoogleProvider();\n\nexport interface GoogleUserInfo {\n aud: string;\n azp: string;\n email: string;\n email_verified: boolean;\n exp: number;\n family_name: string;\n given_name: string;\n hd?: string;\n iat: number;\n iss: string;\n jti?: string;\n locale?: string;\n name: string;\n nbf?: number;\n picture: string;\n sub: string;\n nonce?: string;\n}\n\nexport interface GoogleToken extends OAuth2Token {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n id_token: string;\n scope: string;\n}\n\n// android,ios has different client_id and redirect_uri\nexport interface GoogleAppCredential extends NativeCredential {\n state: string;\n code: string;\n client_id: string;\n redirect_uri: string;\n}\n\nexport interface GoogleErrorResponse {\n error:\n | 'invalid_request'\n | 'invalid_client'\n | 'invalid_grant'\n | 'invalid_token'\n | 'invalid_scope'\n | 'unauthorized_client'\n | 'unsupported_grant_type'\n | 'access_denied'\n | 'server_error';\n error_description: string;\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAO5B,SAAS,wBAAwB,2BAA2B,qBAAqB;AAE1E,SAAS,uBAAuC;AACrD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,WAAW;AAAA;AAAA,IAEX,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,uBAAuB,QAAQ;AAC7B,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,YAAM,WAAW,MAAM,0BAA0B,EAAE,GAAG,QAAQ,UAAU,KAAK,SAAS,CAAC;AACvF,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,SAAS,GAAG;AAC9B,gBAAU,UAAU,sBAAsB;AAC1C,gBAAU,KAAK,WAAW,uBAAuB;AACjD,YAAM,OAAO,MAAM,cAA8B,UAAU,KAAK,SAAS;AACzE,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,UACN,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,SAAS,KAAK;AAAA,UACd,OAAO,KAAK;AAAA,UACZ,gBAAgB,KAAK;AAAA,UACrB,YAAY,KAAK;AAAA,UACjB,aAAa,KAAK;AAAA,UAClB,QAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,kBAAkB,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,GAA4B;AACpF,gBAAU,YAAY,MAAM,kBAAkB;AAC9C,YAAM,EAAE,KAAK,IAAI;AACjB,YAAM,EAAE,SAAS,IAAI;AACrB,YAAM,WAAW,MAAM,0BAA0B,EAAE,MAAM,UAAU,GAAG,OAAO,CAAC;AAC9E,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,EAAE,OAAO,kBAAkB,IAAK,MAAM,SAAS,KAAK;AAC1D,cAAM,IAAI,YAAY,SAAS,QAAQ,OAAO,iBAAiB;AAAA,MACjE;AACA,YAAM,QAAS,MAAM,SAAS,KAAK;AACnC,YAAM,WAAW,MAAM,KAAK,YAAY,KAAK;AAC7C,aAAO,EAAE,OAAO,SAAS;AAAA,IAC3B;AAAA,IACA,MAAM,aAAa,UAAkB;AACnC,gBAAU,UAAU,sBAAsB;AAC1C,gBAAU,KAAK,WAAW,uBAAuB;AACjD,YAAM,OAAO,MAAM,cAA8B,UAAU,KAAK,SAAS;AACzE,aAAO;AAAA,QACL,OAAO;AAAA,UACL;AAAA,UACA,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,eAAe;AAAA,UACf,OAAO;AAAA,QACT;AAAA,QACA,UAAU;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,YACN,KAAK,KAAK;AAAA,YACV,MAAM,KAAK;AAAA,YACX,SAAS,KAAK;AAAA,YACd,OAAO,KAAK;AAAA,YACZ,gBAAgB,KAAK;AAAA,YACrB,YAAY,KAAK;AAAA,YACjB,aAAa,KAAK;AAAA,YAClB,QAAQ,KAAK;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,SAAS,qBAAqB;","names":[]}
|
|
@@ -73,7 +73,7 @@ function createWechatProvider(options = { isWechatBrowser: false }) {
|
|
|
73
73
|
claims: {
|
|
74
74
|
sub: data.unionid ?? data.openid,
|
|
75
75
|
name: data.nickname,
|
|
76
|
-
picture: data.headimgurl.split("/").slice(0, -1).join("/")
|
|
76
|
+
picture: `${data.headimgurl.split("/").slice(0, -1).join("/")}/0`,
|
|
77
77
|
gender: data.sex === 1 ? "male" : data.sex === 2 ? "female" : void 0
|
|
78
78
|
}
|
|
79
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/wechat.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\n\nexport type Options = { isWechatBrowser: boolean };\n\n/**\n * reference: https://developers.weixin.qq.com/doc/offiaccount/en/OA_Web_Apps/Wechat_webpage_authorization.html\n */\nexport function createWechatProvider(options: Options = { isWechatBrowser: false }): Provider {\n const { isWechatBrowser } = options;\n return {\n authorizationUri: isWechatBrowser\n ? 'https://open.weixin.qq.com/connect/oauth2/authorize'\n : 'https://open.weixin.qq.com/connect/qrconnect',\n tokenUri: 'https://api.weixin.qq.com/sns/oauth2/access_token',\n tokenRefreshUri: 'https://api.weixin.qq.com/sns/oauth2/refresh_token',\n userInfoUri: 'https://api.weixin.qq.com/sns/userinfo',\n defaultScope: [isWechatBrowser ? 'snsapi_userinfo' : 'snsapi_login'],\n createAuthorizationUri(params) {\n const url = new URL(this.authorizationUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('scope', (params.scope ?? this.defaultScope).join(','));\n url.searchParams.set('redirect_uri', params.redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('state', params.state);\n return url;\n },\n async exchangeAuthorizationCode(params) {\n const url = new URL(this.tokenUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('secret', params.clientSecret);\n url.searchParams.set('code', params.code);\n url.searchParams.set('grant_type', 'authorization_code');\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n async getUserInfo({ access_token, openid }) {\n invariant(this.userInfoUri, 'userInfoUri is required');\n invariant(openid && typeof openid === 'string', 'openid is required');\n const url = new URL(this.userInfoUri);\n url.searchParams.set('access_token', access_token);\n url.searchParams.set('openid', openid);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n const data = (await response.json()) as WechatUserInfo;\n\n return {\n data,\n claims: {\n sub: data.unionid ?? data.openid,\n name: data.nickname,\n picture: data.headimgurl.split('/').slice(0, -1).join('/')
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/wechat.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\n\nexport type Options = { isWechatBrowser: boolean };\n\n/**\n * reference: https://developers.weixin.qq.com/doc/offiaccount/en/OA_Web_Apps/Wechat_webpage_authorization.html\n */\nexport function createWechatProvider(options: Options = { isWechatBrowser: false }): Provider {\n const { isWechatBrowser } = options;\n return {\n authorizationUri: isWechatBrowser\n ? 'https://open.weixin.qq.com/connect/oauth2/authorize'\n : 'https://open.weixin.qq.com/connect/qrconnect',\n tokenUri: 'https://api.weixin.qq.com/sns/oauth2/access_token',\n tokenRefreshUri: 'https://api.weixin.qq.com/sns/oauth2/refresh_token',\n userInfoUri: 'https://api.weixin.qq.com/sns/userinfo',\n defaultScope: [isWechatBrowser ? 'snsapi_userinfo' : 'snsapi_login'],\n createAuthorizationUri(params) {\n const url = new URL(this.authorizationUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('scope', (params.scope ?? this.defaultScope).join(','));\n url.searchParams.set('redirect_uri', params.redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('state', params.state);\n return url;\n },\n async exchangeAuthorizationCode(params) {\n const url = new URL(this.tokenUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('secret', params.clientSecret);\n url.searchParams.set('code', params.code);\n url.searchParams.set('grant_type', 'authorization_code');\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n async getUserInfo({ access_token, openid }) {\n invariant(this.userInfoUri, 'userInfoUri is required');\n invariant(openid && typeof openid === 'string', 'openid is required');\n const url = new URL(this.userInfoUri);\n url.searchParams.set('access_token', access_token);\n url.searchParams.set('openid', openid);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n const data = (await response.json()) as WechatUserInfo;\n\n return {\n data,\n claims: {\n sub: data.unionid ?? data.openid,\n name: data.nickname,\n picture: `${data.headimgurl.split('/').slice(0, -1).join('/')}/0`,\n gender: data.sex === 1 ? 'male' : data.sex === 2 ? 'female' : undefined,\n },\n };\n },\n async refreshAccessToken(params) {\n invariant(this.tokenRefreshUri, 'tokenRefreshUri is required');\n const url = new URL(this.tokenRefreshUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('grant_type', 'refresh_token');\n url.searchParams.set('refresh_token', params.refreshToken);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n };\n}\n\nexport const wechat = createWechatProvider();\n\nexport interface WechatUserInfo {\n openid: string;\n nickname: string;\n sex: 0 | 1 | 2; // 0: unknown, 1: male, 2: female\n province: string;\n city: string;\n country: string;\n /**\n * User's profile photo. The last numeric value represents the size of a square profile photo\n * (The value can be 0, 46, 64, 96, or 132. The value 0 represents a 640*640 square profile\n * photo). This parameter is left blank if a user has no profile photo. If the user changes the\n * profile photo, the URL of the original profile photo will expire.\n * e.g. http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46\n */\n headimgurl: string;\n privilege: string[];\n unionid?: string;\n}\n\nexport interface WechatToken extends OAuth2Token {\n access_token: string;\n expires_in: number;\n refresh_token: string;\n openid: string;\n scope: string;\n unionid?: string;\n}\n\ninterface WechatErrorResponse {\n errcode: number;\n errmsg: string;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -48,7 +48,7 @@ function createWechatProvider(options = { isWechatBrowser: false }) {
|
|
|
48
48
|
claims: {
|
|
49
49
|
sub: data.unionid ?? data.openid,
|
|
50
50
|
name: data.nickname,
|
|
51
|
-
picture: data.headimgurl.split("/").slice(0, -1).join("/")
|
|
51
|
+
picture: `${data.headimgurl.split("/").slice(0, -1).join("/")}/0`,
|
|
52
52
|
gender: data.sex === 1 ? "male" : data.sex === 2 ? "female" : void 0
|
|
53
53
|
}
|
|
54
54
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/wechat.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\n\nexport type Options = { isWechatBrowser: boolean };\n\n/**\n * reference: https://developers.weixin.qq.com/doc/offiaccount/en/OA_Web_Apps/Wechat_webpage_authorization.html\n */\nexport function createWechatProvider(options: Options = { isWechatBrowser: false }): Provider {\n const { isWechatBrowser } = options;\n return {\n authorizationUri: isWechatBrowser\n ? 'https://open.weixin.qq.com/connect/oauth2/authorize'\n : 'https://open.weixin.qq.com/connect/qrconnect',\n tokenUri: 'https://api.weixin.qq.com/sns/oauth2/access_token',\n tokenRefreshUri: 'https://api.weixin.qq.com/sns/oauth2/refresh_token',\n userInfoUri: 'https://api.weixin.qq.com/sns/userinfo',\n defaultScope: [isWechatBrowser ? 'snsapi_userinfo' : 'snsapi_login'],\n createAuthorizationUri(params) {\n const url = new URL(this.authorizationUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('scope', (params.scope ?? this.defaultScope).join(','));\n url.searchParams.set('redirect_uri', params.redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('state', params.state);\n return url;\n },\n async exchangeAuthorizationCode(params) {\n const url = new URL(this.tokenUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('secret', params.clientSecret);\n url.searchParams.set('code', params.code);\n url.searchParams.set('grant_type', 'authorization_code');\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n async getUserInfo({ access_token, openid }) {\n invariant(this.userInfoUri, 'userInfoUri is required');\n invariant(openid && typeof openid === 'string', 'openid is required');\n const url = new URL(this.userInfoUri);\n url.searchParams.set('access_token', access_token);\n url.searchParams.set('openid', openid);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n const data = (await response.json()) as WechatUserInfo;\n\n return {\n data,\n claims: {\n sub: data.unionid ?? data.openid,\n name: data.nickname,\n picture: data.headimgurl.split('/').slice(0, -1).join('/')
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/wechat.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\n\nexport type Options = { isWechatBrowser: boolean };\n\n/**\n * reference: https://developers.weixin.qq.com/doc/offiaccount/en/OA_Web_Apps/Wechat_webpage_authorization.html\n */\nexport function createWechatProvider(options: Options = { isWechatBrowser: false }): Provider {\n const { isWechatBrowser } = options;\n return {\n authorizationUri: isWechatBrowser\n ? 'https://open.weixin.qq.com/connect/oauth2/authorize'\n : 'https://open.weixin.qq.com/connect/qrconnect',\n tokenUri: 'https://api.weixin.qq.com/sns/oauth2/access_token',\n tokenRefreshUri: 'https://api.weixin.qq.com/sns/oauth2/refresh_token',\n userInfoUri: 'https://api.weixin.qq.com/sns/userinfo',\n defaultScope: [isWechatBrowser ? 'snsapi_userinfo' : 'snsapi_login'],\n createAuthorizationUri(params) {\n const url = new URL(this.authorizationUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('scope', (params.scope ?? this.defaultScope).join(','));\n url.searchParams.set('redirect_uri', params.redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('state', params.state);\n return url;\n },\n async exchangeAuthorizationCode(params) {\n const url = new URL(this.tokenUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('secret', params.clientSecret);\n url.searchParams.set('code', params.code);\n url.searchParams.set('grant_type', 'authorization_code');\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n async getUserInfo({ access_token, openid }) {\n invariant(this.userInfoUri, 'userInfoUri is required');\n invariant(openid && typeof openid === 'string', 'openid is required');\n const url = new URL(this.userInfoUri);\n url.searchParams.set('access_token', access_token);\n url.searchParams.set('openid', openid);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n const data = (await response.json()) as WechatUserInfo;\n\n return {\n data,\n claims: {\n sub: data.unionid ?? data.openid,\n name: data.nickname,\n picture: `${data.headimgurl.split('/').slice(0, -1).join('/')}/0`,\n gender: data.sex === 1 ? 'male' : data.sex === 2 ? 'female' : undefined,\n },\n };\n },\n async refreshAccessToken(params) {\n invariant(this.tokenRefreshUri, 'tokenRefreshUri is required');\n const url = new URL(this.tokenRefreshUri);\n url.searchParams.set('appid', params.clientId);\n url.searchParams.set('grant_type', 'refresh_token');\n url.searchParams.set('refresh_token', params.refreshToken);\n const response = await fetch(url.href);\n if (!response.ok) {\n const { errcode, errmsg } = (await response.json()) as WechatErrorResponse;\n throw new OAuth2Error(response.status, errmsg, `errcode: ${errcode}`);\n }\n return (await response.json()) as WechatToken;\n },\n };\n}\n\nexport const wechat = createWechatProvider();\n\nexport interface WechatUserInfo {\n openid: string;\n nickname: string;\n sex: 0 | 1 | 2; // 0: unknown, 1: male, 2: female\n province: string;\n city: string;\n country: string;\n /**\n * User's profile photo. The last numeric value represents the size of a square profile photo\n * (The value can be 0, 46, 64, 96, or 132. The value 0 represents a 640*640 square profile\n * photo). This parameter is left blank if a user has no profile photo. If the user changes the\n * profile photo, the URL of the original profile photo will expire.\n * e.g. http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46\n */\n headimgurl: string;\n privilege: string[];\n unionid?: string;\n}\n\nexport interface WechatToken extends OAuth2Token {\n access_token: string;\n expires_in: number;\n refresh_token: string;\n openid: string;\n scope: string;\n unionid?: string;\n}\n\ninterface WechatErrorResponse {\n errcode: number;\n errmsg: string;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -79,7 +79,7 @@ function createXProvider(options) {
|
|
|
79
79
|
throw new import_error.OAuth2Error(
|
|
80
80
|
response.status,
|
|
81
81
|
"invalid_request",
|
|
82
|
-
|
|
82
|
+
`Failed to fetch user info: ${errors.at(0)?.detail ?? errors.at(0)?.title}`
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
85
|
const profile = await response.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { OAuth2Token, Provider } from '../types';\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 createXProvider(options?: XOptions): Provider {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRefreshUri: '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.pkce) throw new Error('pkce 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.pkce) throw new Error('pkce 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 XToken;\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
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\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 createXProvider(options?: XOptions): Provider {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRefreshUri: '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.pkce) throw new Error('pkce 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.pkce) throw new Error('pkce 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 XToken;\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 invariant(this.tokenRefreshUri, 'tokenRefreshUri is required');\n const response = await refreshAccessToken({\n ...params,\n tokenUri: this.tokenRefreshUri,\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 XToken;\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\nexport const x = createXProvider();\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\nexport interface XToken extends OAuth2Token {\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;AAAA,mBAA0B;AAC1B,mBAA4B;AAE5B,oBAKO;AAMP,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,gBAAgB,SAA8B;AAC5D,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,gBAAgB;AAAA;AAAA,IAEhB,aAAa;AAAA,IACb,cAAc,CAAC,cAAc,cAAc,gBAAgB;AAAA,IAC3D,uBAAuB,QAAQ;AAC7B,UAAI,CAAC,OAAO,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAC1D,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,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAC1D,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,kCAAU,cAAc,0BAA0B;AAClD,kCAAU,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,8BAA8B,OAAO,GAAG,CAAC,GAAG,UAAU,OAAO,GAAG,CAAC,GAAG,KAAK;AAAA,QAC3E;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,kCAAU,KAAK,iBAAiB,6BAA6B;AAC7D,YAAM,WAAW,UAAM,kCAAmB;AAAA,QACxC,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,QAAQ;AACxB,kCAAU,KAAK,gBAAgB,4BAA4B;AAC3D,iBAAO,2BAAY;AAAA,QACjB,GAAG;AAAA,QACH,gBAAgB,KAAK;AAAA,QACrB,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,IAAM,IAAI,gBAAgB;","names":[]}
|
|
@@ -59,7 +59,7 @@ function createXProvider(options) {
|
|
|
59
59
|
throw new OAuth2Error(
|
|
60
60
|
response.status,
|
|
61
61
|
"invalid_request",
|
|
62
|
-
|
|
62
|
+
`Failed to fetch user info: ${errors.at(0)?.detail ?? errors.at(0)?.title}`
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
const profile = await response.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport { OAuth2Token, Provider } from '../types';\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 createXProvider(options?: XOptions): Provider {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRefreshUri: '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.pkce) throw new Error('pkce 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.pkce) throw new Error('pkce 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 XToken;\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
|
|
1
|
+
{"version":3,"sources":["../../../src/oauth2/provider/x.ts"],"sourcesContent":["import { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { OAuth2Token, Provider } from '../types';\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 createXProvider(options?: XOptions): Provider {\n return {\n authorizationUri: 'https://x.com/i/oauth2/authorize',\n tokenUri: 'https://api.x.com/2/oauth2/token',\n tokenRefreshUri: '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.pkce) throw new Error('pkce 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.pkce) throw new Error('pkce 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 XToken;\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 invariant(this.tokenRefreshUri, 'tokenRefreshUri is required');\n const response = await refreshAccessToken({\n ...params,\n tokenUri: this.tokenRefreshUri,\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 XToken;\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\nexport const x = createXProvider();\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\nexport interface XToken extends OAuth2Token {\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,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAE5B;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,gBAAgB,SAA8B;AAC5D,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,gBAAgB;AAAA;AAAA,IAEhB,aAAa;AAAA,IACb,cAAc,CAAC,cAAc,cAAc,gBAAgB;AAAA,IAC3D,uBAAuB,QAAQ;AAC7B,UAAI,CAAC,OAAO,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAC1D,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,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAC1D,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,8BAA8B,OAAO,GAAG,CAAC,GAAG,UAAU,OAAO,GAAG,CAAC,GAAG,KAAK;AAAA,QAC3E;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,gBAAU,KAAK,iBAAiB,6BAA6B;AAC7D,YAAM,WAAW,MAAM,mBAAmB;AAAA,QACxC,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,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;AAEO,IAAM,IAAI,gBAAgB;","names":[]}
|