UNPKG

@randajan/oauth2-client

Version:

Lightweight Node.js helper that streamlines OAuth 2.0 and service-account authentication for all Google APIs, giving downstream packages hassle-free token acquisition and refresh

8 lines (7 loc) 12.2 kB
{ "version": 3, "sources": ["../../../src/google/scopes.js", "../../../src/google/Client.js", "../../../src/consts.js", "../../../src/google/Account.js", "../../../src/errors.js"], "sourcesContent": ["\r\n\r\nconst _scopePrefix = \"https://www.googleapis.com/auth/\";\r\nexport const _defaultScopes = [\"openid\", \"userinfo.profile\", \"userinfo.email\"];\r\n\r\nconst effaceScope = (scope, full=false)=>{\r\n scope = String(scope).replace(/[\\s\\n\\r]+/g, \" \").trim().toLowerCase();\r\n if (scope === \"openid\") { return scope; }\r\n const sw = scope.startsWith(_scopePrefix);\r\n return sw === full ? scope : full ? _scopePrefix+scope : scope.substring(_scopePrefix.length);\r\n}\r\n\r\nexport const effaceScopes = (scopes, full=false, ensureScopes=[])=>{\r\n if (typeof scopes === \"string\") { scopes = scopes.split(\" \"); }\r\n if (!Array.isArray(scopes)) { scopes = ensureScopes; }\r\n else { scopes = scopes.concat(ensureScopes); }\r\n\r\n const r = new Set();\r\n for (let scope of scopes) {\r\n if (scope) { scope = effaceScope(scope, full); }\r\n if (scope) { r.add(scope); }\r\n }\r\n return [...r];\r\n}", "import { google } from \"googleapis\";\r\nimport { vault } from \"../consts\";\r\nimport { _defaultScopes, effaceScopes } from \"./scopes\";\r\nimport { GoogleAccount } from \"./Account\";\r\nimport { extendURL, isValidURL, objFromBase64, objToBase64, validateFn, validateURL } from \"../tools\";\r\nimport { RedirectError } from \"../errors\";\r\n\r\n\r\n//add to options:\r\n// access_type - offline?\r\n// scopes - [\"openid\", \"userinfo.profile\", \"userinfo.email\"] are static default\r\n// clientId\r\n// clientSecret\r\n// redirectUri - backend code resolve URL\r\n// landingUri - frontend ok redirect URL\r\n// fallbackUri - error handling redirect will be used with query.errorCode && query.errorMessage\r\n// onAuth - register new account, can return customUri redirect\r\n// onRenew - tokens auto refresh, should store at db, no return expects\r\n// extra - will be passed to google.auth.OAuth2(...)\r\n\r\nexport class GoogleOAuth2 {\r\n\r\n constructor(options = {}) {\r\n const {\r\n isOffline, scopes, clientId, clientSecret,\r\n redirectUri, landingUri, fallbackUri,\r\n onAuth, onRenew, getCredentials, extra\r\n } = options;\r\n\r\n const _p = { };\r\n\r\n _p.isOffline = !!isOffline;\r\n _p.defaultScopes = effaceScopes(scopes, true, _defaultScopes);\r\n _p.landingUri = validateURL(false, landingUri, \"options.landingUri\");\r\n _p.fallbackUri = validateURL(true, fallbackUri, \"options.fallbackUri\");\r\n\r\n _p.onAuth = validateFn(true, onAuth, \"options.onAuth\");\r\n _p.onRenew = validateFn(true, onRenew, \"options.onRenew\");\r\n _p.getCredentials = validateFn(false, getCredentials, \"options.getCredentials\");\r\n\r\n const commonOptions = {\r\n ...(extra || {}),\r\n clientId,\r\n clientSecret,\r\n redirectUri:validateURL(true, redirectUri, \"options.redirectUri\")\r\n }\r\n\r\n _p.createAuth = _=>new google.auth.OAuth2(commonOptions);\r\n _p.auth = _p.createAuth();\r\n\r\n this._fallbackRedirect = (majorCode, err)=>{\r\n const c = RedirectError.is(err) ? err.code : 0;\r\n return extendURL(_p.fallbackUri, {errorCode:majorCode*100+c, errorMessage:err.message});\r\n }\r\n\r\n vault.set(this, _p);\r\n }\r\n\r\n account(credentials, ...args) {\r\n const { getCredentials } = vault.get(this);\r\n const c = getCredentials ? getCredentials(credentials, ...args) : credentials;\r\n return (c instanceof Promise) ? c.then(cr=>new GoogleAccount(this, cr)) : new GoogleAccount(this, c);\r\n }\r\n\r\n _getInitAuthURL(options={}) {\r\n const _p = vault.get(this);\r\n const { landingUri, state, scopes, extra } = options;\r\n\r\n if ((landingUri || !_p.landingUri) && !isValidURL(landingUri)) {\r\n throw new RedirectError(1, \"Bad request. Missing valid 'landingUri'\");\r\n }\r\n\r\n return _p.auth.generateAuthUrl({\r\n ...(extra || {}),\r\n access_type: _p.isOffline ? \"offline\" : \"online\",\r\n scope: effaceScopes(scopes, true, _p.defaultScopes),\r\n state: objToBase64([ landingUri || _p.landingUri, state ])\r\n });\r\n\r\n }\r\n\r\n getInitAuthURL(options={}) {\r\n try { return this._getInitAuthURL(options); }\r\n catch(err) { return this._fallbackRedirect(1, err);}\r\n }\r\n\r\n async _getExitAuthURL({code, state}, context) {\r\n const _p = vault.get(this);\r\n\r\n if (!code) { throw new RedirectError(201, \"Bad request. Missing 'code'\"); }\r\n\r\n const [ landingUri, passedState ] = objFromBase64(state);\r\n if (!isValidURL(landingUri)) { throw new RedirectError(202, \"Bad request. Missing valid 'state'\"); }\r\n\r\n const { tokens } = await _p.auth.getToken(code);\r\n const account = new GoogleAccount(this, tokens);\r\n \r\n const customUri = await _p.onAuth(account, { context, landingUri, state:passedState });\r\n return customUri || landingUri;\r\n }\r\n\r\n getExitAuthURL({code, state}, context) {\r\n try { return this._getExitAuthURL({ code, state }, context); }\r\n catch(err) { return this._fallbackRedirect(2, err);}\r\n }\r\n\r\n}", "\r\n\r\nexport const vault = new WeakMap();", "import { google } from \"googleapis\";\r\nimport { vault } from \"../consts\";\r\nimport { solids } from \"@randajan/props\";\r\nimport { effaceScopes } from \"./scopes\";\r\n\r\nexport class GoogleAccount {\r\n\r\n constructor(client, credentials={}) {\r\n\r\n const { access_token, refresh_token, expiry_date } = credentials;\r\n\r\n if (refresh_token && !expiry_date) {\r\n throw new Error(`OAuth2 account credentials 'refresh_token' must be provided with 'expiry_date'`);\r\n }\r\n\r\n if (!access_token && !refresh_token) {\r\n throw new Error(`OAuth2 account credentials 'access_token' of 'refresh_token' must be provided`);\r\n }\r\n\r\n const { createAuth, onRenew } = vault.get(client);\r\n\r\n const auth = createAuth();\r\n auth.setCredentials(credentials);\r\n auth.on('tokens', _=>{ onRenew(this); });\r\n\r\n solids(this, {\r\n client,\r\n auth,\r\n });\r\n }\r\n\r\n oauth2() {\r\n return google.oauth2({ auth: this.auth, version: 'v2' });\r\n }\r\n\r\n async uid() {\r\n const { id } = await this.profile();\r\n return `google:${id}`;\r\n }\r\n\r\n async profile() {\r\n const { data } = await this.oauth2().userinfo.get();\r\n return data;\r\n }\r\n\r\n async tokens() {\r\n const { token } = await this.auth.getAccessToken();\r\n\r\n return { ...this.auth.credentials, access_token: token };\r\n }\r\n\r\n async scopes() {\r\n const { auth } = this;\r\n\r\n if (auth.credentials?.scope) {\r\n return effaceScopes(auth.credentials.scope);\r\n }\r\n\r\n const { token } = await auth.getAccessToken();\r\n if (!token) { return []; }\r\n\r\n const info = await auth.getTokenInfo(token);\r\n if (!info) { return []; }\r\n\r\n return effaceScopes(info.scopes);\r\n }\r\n\r\n}", "\r\n\r\n\r\n\r\nexport class RedirectError extends Error {\r\n\r\n static is(any) {\r\n return any instanceof RedirectError;\r\n }\r\n\r\n constructor(code, message, options) {\r\n super(message, options);\r\n this.code = code;\r\n }\r\n}"], "mappings": "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", "names": ["google", "google"] }