n8n
Version:
n8n Workflow Automation Tool
570 lines • 28.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var OauthService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OauthService = exports.OauthVersion = exports.skipAuthOnOAuthCallback = void 0;
exports.shouldSkipAuthOnOAuthCallback = shouldSkipAuthOnOAuthCallback;
const backend_common_1 = require("@n8n/backend-common");
const config_1 = require("@n8n/config");
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const csrf_1 = __importDefault(require("csrf"));
const n8n_core_1 = require("n8n-core");
const n8n_workflow_1 = require("n8n-workflow");
const constants_1 = require("../constants");
const credentials_finder_service_1 = require("../credentials/credentials-finder.service");
const credentials_helper_1 = require("../credentials-helper");
const auth_error_1 = require("../errors/response-errors/auth.error");
const bad_request_error_1 = require("../errors/response-errors/bad-request.error");
const not_found_error_1 = require("../errors/response-errors/not-found.error");
const validate_oauth_url_1 = require("../oauth/validate-oauth-url");
const url_service_1 = require("../services/url.service");
const WorkflowExecuteAdditionalData = __importStar(require("../workflow-execute-additional-data"));
const client_oauth2_1 = require("@n8n/client-oauth2");
const axios_1 = __importDefault(require("axios"));
const oauth2_dynamic_client_registration_schema_1 = require("../controllers/oauth/oauth2-dynamic-client-registration.schema");
const pkce_challenge_1 = __importDefault(require("pkce-challenge"));
const qs = __importStar(require("querystring"));
const split_1 = __importDefault(require("lodash/split"));
const external_hooks_1 = require("../external-hooks");
const crypto_1 = require("crypto");
const oauth_1_0a_1 = __importDefault(require("oauth-1.0a"));
const types_1 = require("./types");
Object.defineProperty(exports, "OauthVersion", { enumerable: true, get: function () { return types_1.OauthVersion; } });
const dynamic_credentials_proxy_1 = require("../credentials/dynamic-credentials-proxy");
function shouldSkipAuthOnOAuthCallback() {
const value = process.env.N8N_SKIP_AUTH_ON_OAUTH_CALLBACK?.toLowerCase() ?? 'false';
return value === 'true';
}
exports.skipAuthOnOAuthCallback = shouldSkipAuthOnOAuthCallback();
let OauthService = OauthService_1 = class OauthService {
constructor(logger, credentialsHelper, credentialsRepository, credentialsFinderService, urlService, globalConfig, externalHooks, cipher, dynamicCredentialsProxy) {
this.logger = logger;
this.credentialsHelper = credentialsHelper;
this.credentialsRepository = credentialsRepository;
this.credentialsFinderService = credentialsFinderService;
this.urlService = urlService;
this.globalConfig = globalConfig;
this.externalHooks = externalHooks;
this.cipher = cipher;
this.dynamicCredentialsProxy = dynamicCredentialsProxy;
}
validateOAuthUrlOrThrow(url) {
try {
(0, validate_oauth_url_1.validateOAuthUrl)(url);
}
catch (e) {
this.logger.error('Invalid OAuth URL', { url, error: e });
throw e;
}
}
getBaseUrl(oauthVersion) {
const restUrl = `${this.urlService.getInstanceBaseUrl()}/${this.globalConfig.endpoints.rest}`;
return `${restUrl}/oauth${oauthVersion}-credential`;
}
async getCredentialForUpdate(req) {
const { id: credentialId } = req.query;
if (!credentialId) {
throw new bad_request_error_1.BadRequestError('Required credential ID is missing');
}
const credential = await this.credentialsFinderService.findCredentialForUser(credentialId, req.user, ['credential:update']);
if (!credential) {
this.logger.error('OAuth credential authorization failed because the current user does not have the correct permissions', { userId: req.user.id, credentialId });
throw new not_found_error_1.NotFoundError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL);
}
return credential;
}
async getAdditionalData() {
return await WorkflowExecuteAdditionalData.getBase();
}
async getDecryptedDataForAuthUri(credential, additionalData) {
return await this.getDecryptedData(credential, additionalData, false);
}
async getDecryptedDataForCallback(credential, additionalData) {
return await this.getDecryptedData(credential, additionalData, true);
}
async getDecryptedData(credential, additionalData, raw) {
return await this.credentialsHelper.getDecrypted(additionalData, credential, credential.type, 'internal', undefined, raw);
}
async applyDefaultsAndOverwrites(credential, decryptedData, additionalData) {
return (await this.credentialsHelper.applyDefaultsAndOverwrites(additionalData, decryptedData, credential.type, 'internal', undefined, undefined));
}
async encryptAndSaveData(credential, toUpdate, toDelete = []) {
if (toUpdate.oauthTokenData && typeof toUpdate.oauthTokenData === 'object') {
const identifier = OauthService_1.extractAccountIdentifier(toUpdate.oauthTokenData);
if (identifier) {
toUpdate.accountIdentifier = identifier;
}
}
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.data);
await credentials.updateData(toUpdate, toDelete);
await this.credentialsRepository.update(credential.id, {
...credentials.getDataToSave(),
updatedAt: new Date(),
});
}
static extractAccountIdentifier(tokenData) {
for (const key of ['email', 'login', 'username', 'user', 'account']) {
if (typeof tokenData[key] === 'string' && tokenData[key]) {
return tokenData[key];
}
}
if (typeof tokenData.id_token === 'string') {
const parts = tokenData.id_token.split('.');
if (parts.length === 3) {
try {
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
if (typeof payload.email === 'string' && payload.email) {
return payload.email;
}
if (typeof payload.preferred_username === 'string' && payload.preferred_username) {
return payload.preferred_username;
}
}
catch { }
}
}
const authedUser = tokenData.authed_user;
if (authedUser && typeof authedUser === 'object') {
const user = authedUser;
if (typeof user.id === 'string' && user.id) {
return user.id;
}
}
return undefined;
}
async getCredentialWithoutUser(credentialId) {
return await this.credentialsRepository.findOneBy({ id: credentialId });
}
async createCsrfState(data) {
const token = new csrf_1.default();
const csrfSecret = token.secretSync();
const state = {
token: token.create(csrfSecret),
createdAt: Date.now(),
data: await this.cipher.encryptV2(JSON.stringify(data)),
};
const base64State = Buffer.from(JSON.stringify(state)).toString('base64');
return [csrfSecret, base64State];
}
async decodeCsrfState(encodedState, req) {
const errorMessage = 'Invalid state format';
const decodedState = Buffer.from(encodedState, 'base64').toString();
const decoded = (0, n8n_workflow_1.jsonParse)(decodedState, {
errorMessage,
});
const decryptedState = (0, n8n_workflow_1.jsonParse)(await this.cipher.decryptV2(decoded.data), {
errorMessage,
});
if (typeof decryptedState.cid !== 'string' || typeof decoded.token !== 'string') {
throw new n8n_workflow_1.UnexpectedError(errorMessage);
}
if (decryptedState.origin === 'dynamic-credential') {
return [
{ ...decoded, ...decryptedState },
await this.getCredentialWithoutUser(decryptedState.cid),
];
}
if (exports.skipAuthOnOAuthCallback) {
return [
{ ...decoded, ...decryptedState },
await this.getCredentialWithoutUser(decryptedState.cid),
];
}
if (req.user?.id === undefined || decryptedState.userId !== req.user.id) {
throw new auth_error_1.AuthError('Unauthorized');
}
const credential = await this.credentialsFinderService.findCredentialForUser(decryptedState.cid, req.user, ['credential:update']);
return [{ ...decoded, ...decryptedState }, credential];
}
verifyCsrfState(decrypted, state) {
const token = new csrf_1.default();
return (Date.now() - state.createdAt <= types_1.MAX_CSRF_AGE &&
decrypted.csrfSecret !== undefined &&
token.verify(decrypted.csrfSecret, state.token));
}
async resolveCredential(req) {
const { state: encodedState } = req.query;
const [state, credential] = await this.decodeCsrfState(encodedState, req);
if (!credential) {
throw new not_found_error_1.NotFoundError(constants_1.RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL);
}
const additionalData = await this.getAdditionalData();
const decryptedDataOriginal = await this.getDecryptedDataForCallback(credential, additionalData);
const oauthCredentials = await this.applyDefaultsAndOverwrites(credential, decryptedDataOriginal, additionalData);
if (!this.verifyCsrfState(decryptedDataOriginal, state)) {
throw new n8n_workflow_1.UnexpectedError('The OAuth callback state is invalid!');
}
return [credential, decryptedDataOriginal, oauthCredentials, state];
}
renderCallbackError(res, message, reason) {
res.render('oauth-error-callback', { error: { message, reason } });
}
async getOAuthCredentials(credential) {
const additionalData = await this.getAdditionalData();
const decryptedDataOriginal = await this.getDecryptedDataForAuthUri(credential, additionalData);
if (decryptedDataOriginal?.scope &&
credential.type.includes('OAuth2') &&
!constants_1.GENERIC_OAUTH2_CREDENTIALS_WITH_EDITABLE_SCOPE.includes(credential.type) &&
!this.hasEditableScopeProperty(credential.type)) {
delete decryptedDataOriginal.scope;
}
const oauthCredentials = await this.applyDefaultsAndOverwrites(credential, decryptedDataOriginal, additionalData);
return oauthCredentials;
}
hasEditableScopeProperty(credentialType) {
try {
const properties = this.credentialsHelper.getCredentialsProperties(credentialType);
const scopeProperty = properties.find((property) => property.name === 'scope');
return scopeProperty !== undefined && scopeProperty.type !== 'hidden';
}
catch {
return false;
}
}
async generateAOauth2AuthUri(credential, csrfData) {
const oauthCredentials = await this.getOAuthCredentials(credential);
const toUpdate = {};
if (oauthCredentials.useDynamicClientRegistration && oauthCredentials.serverUrl) {
this.validateOAuthUrlOrThrow(oauthCredentials.serverUrl);
let authorizationServerUrl;
try {
const protectedResourceMetadata = await this.discoverProtectedResourceMetadata(oauthCredentials.serverUrl);
authorizationServerUrl = protectedResourceMetadata.authorization_servers[0];
this.validateOAuthUrlOrThrow(authorizationServerUrl);
this.logger.debug('Protected resource discovery succeeded', {
resourceUrl: oauthCredentials.serverUrl,
authorizationServerUrl,
});
}
catch (error) {
if (error instanceof bad_request_error_1.BadRequestError && error.message.includes('OAuth url')) {
throw error;
}
this.logger.debug('Protected resource discovery failed, assuming serverUrl is authorization server', {
serverUrl: oauthCredentials.serverUrl,
error: error.message,
});
authorizationServerUrl = oauthCredentials.serverUrl;
}
const issuerUrl = new URL(authorizationServerUrl);
const pathComponent = issuerUrl.pathname.replace(/\/$/, '');
const pathIsWellKnown = pathComponent.startsWith('/.well-known');
const discoveryUrls = pathComponent && !pathIsWellKnown
? [
`${issuerUrl.origin}/.well-known/oauth-authorization-server${pathComponent}`,
`${issuerUrl.origin}/.well-known/openid-configuration${pathComponent}`,
`${authorizationServerUrl}/.well-known/openid-configuration`,
]
: [
`${issuerUrl.origin}/.well-known/oauth-authorization-server`,
`${issuerUrl.origin}/.well-known/openid-configuration`,
];
let data;
let lastError;
for (const url of discoveryUrls) {
try {
this.validateOAuthUrlOrThrow(url);
const response = await axios_1.default.get(url, {
validateStatus: (status) => status === 200,
});
data = response.data;
break;
}
catch (error) {
lastError = error;
}
}
if (!data) {
throw new bad_request_error_1.BadRequestError(`Failed to discover OAuth2 authorization server metadata. Tried: ${discoveryUrls.join(', ')}. Last error: ${lastError?.message}`);
}
const metadataValidation = oauth2_dynamic_client_registration_schema_1.oAuthAuthorizationServerMetadataSchema.safeParse(data);
if (!metadataValidation.success) {
throw new bad_request_error_1.BadRequestError(`Invalid OAuth2 server metadata: ${metadataValidation.error.issues.map((e) => e.message).join(', ')}`);
}
const { authorization_endpoint, token_endpoint, registration_endpoint, scopes_supported } = metadataValidation.data;
oauthCredentials.authUrl = authorization_endpoint;
oauthCredentials.accessTokenUrl = token_endpoint;
toUpdate.authUrl = authorization_endpoint;
toUpdate.accessTokenUrl = token_endpoint;
const scope = scopes_supported ? scopes_supported.join(' ') : undefined;
if (scope) {
oauthCredentials.scope = scope;
toUpdate.scope = scope;
}
const { grantType, authentication } = this.selectGrantTypeAndAuthenticationMethod(metadataValidation.data.grant_types_supported ?? ['authorization_code', 'implicit'], metadataValidation.data.token_endpoint_auth_methods_supported ?? ['client_secret_basic'], metadataValidation.data.code_challenge_methods_supported ?? []);
oauthCredentials.grantType = grantType;
toUpdate.grantType = grantType;
if (authentication) {
oauthCredentials.authentication = authentication;
toUpdate.authentication = authentication;
}
const { grant_types, token_endpoint_auth_method } = this.mapGrantTypeAndAuthenticationMethod(grantType, authentication);
const registerPayload = {
redirect_uris: [`${this.getBaseUrl(2)}/callback`],
token_endpoint_auth_method,
grant_types,
response_types: ['code'],
client_name: 'n8n',
client_uri: 'https://n8n.io/',
scope,
};
await this.externalHooks.run('oauth2.dynamicClientRegistration', [registerPayload]);
const { data: registerResult } = await axios_1.default.post(registration_endpoint, registerPayload);
const registrationValidation = oauth2_dynamic_client_registration_schema_1.dynamicClientRegistrationResponseSchema.safeParse(registerResult);
if (!registrationValidation.success) {
throw new bad_request_error_1.BadRequestError(`Invalid client registration response: ${registrationValidation.error.issues.map((e) => e.message).join(', ')}`);
}
const { client_id, client_secret } = registrationValidation.data;
oauthCredentials.clientId = client_id;
toUpdate.clientId = client_id;
if (client_secret) {
oauthCredentials.clientSecret = client_secret;
toUpdate.clientSecret = client_secret;
}
}
this.validateOAuthUrlOrThrow(oauthCredentials.authUrl ?? '');
this.validateOAuthUrlOrThrow(oauthCredentials.accessTokenUrl ?? '');
const [csrfSecret, state] = await this.createCsrfState(csrfData);
const oAuthOptions = {
...this.convertCredentialToOptions(oauthCredentials),
state,
};
if (oauthCredentials.authQueryParameters) {
oAuthOptions.query = qs.parse(oauthCredentials.authQueryParameters);
}
await this.externalHooks.run('oauth2.authenticate', [oAuthOptions]);
toUpdate.csrfSecret = csrfSecret;
if (oauthCredentials.grantType === 'pkce') {
const { code_verifier, code_challenge } = await (0, pkce_challenge_1.default)();
oAuthOptions.query = {
...oAuthOptions.query,
code_challenge,
code_challenge_method: 'S256',
};
toUpdate.codeVerifier = code_verifier;
}
await this.encryptAndSaveData(credential, toUpdate);
const oAuthObj = new client_oauth2_1.ClientOAuth2(oAuthOptions);
const returnUri = oAuthObj.code.getUri();
this.logger.debug('OAuth2 authorization url created for credential', {
csrfData,
credentialId: credential.id,
});
return returnUri.toString();
}
async generateAOauth1AuthUri(credential, csrfData) {
const oauthCredentials = await this.getOAuthCredentials(credential);
this.validateOAuthUrlOrThrow(oauthCredentials.authUrl ?? '');
this.validateOAuthUrlOrThrow(oauthCredentials.requestTokenUrl ?? '');
this.validateOAuthUrlOrThrow(oauthCredentials.accessTokenUrl ?? '');
const [csrfSecret, state] = await this.createCsrfState(csrfData);
const signatureMethod = oauthCredentials.signatureMethod;
const oAuthOptions = {
consumer: {
key: oauthCredentials.consumerKey,
secret: oauthCredentials.consumerSecret,
},
signature_method: signatureMethod,
hash_function(base, key) {
const algorithm = types_1.algorithmMap[signatureMethod] ?? 'sha1';
return (0, crypto_1.createHmac)(algorithm, key).update(base).digest('base64');
},
};
const oauthRequestData = {
oauth_callback: `${this.getBaseUrl(1)}/callback?state=${state}`,
};
await this.externalHooks.run('oauth1.authenticate', [oAuthOptions, oauthRequestData]);
const oauth = new oauth_1_0a_1.default(oAuthOptions);
const options = {
method: 'POST',
url: oauthCredentials.requestTokenUrl,
data: oauthRequestData,
};
const data = oauth.toHeader(oauth.authorize(options));
const axiosConfig = {
method: options.method,
url: options.url,
headers: {
...data,
},
};
const { data: response } = await axios_1.default.request(axiosConfig);
if (typeof response !== 'string') {
throw new bad_request_error_1.BadRequestError('Expected string response from OAuth1 request token endpoint, but received invalid response type');
}
const paramsParser = new URLSearchParams(response);
const responseJson = Object.fromEntries(paramsParser.entries());
if (!responseJson.oauth_token) {
throw new bad_request_error_1.BadRequestError('OAuth1 request token response is missing required oauth_token parameter');
}
const returnUri = `${oauthCredentials.authUrl}?oauth_token=${responseJson.oauth_token}`;
await this.encryptAndSaveData(credential, { csrfSecret }, []);
this.logger.debug('OAuth1 authorization url created for credential', {
csrfData,
credentialId: credential.id,
});
return returnUri;
}
convertCredentialToOptions(credential) {
const options = {
clientId: credential.clientId,
clientSecret: credential.clientSecret ?? '',
accessTokenUri: credential.accessTokenUrl ?? '',
authorizationUri: credential.authUrl ?? '',
authentication: credential.authentication ?? 'header',
redirectUri: `${this.getBaseUrl(2)}/callback`,
scopes: (0, split_1.default)(credential.scope ?? 'openid', ','),
scopesSeparator: credential.scope?.includes(',') ? ',' : ' ',
ignoreSSLIssues: credential.ignoreSSLIssues ?? false,
};
if (credential.additionalBodyProperties &&
typeof credential.additionalBodyProperties === 'string') {
const parsedBody = (0, n8n_workflow_1.jsonParse)(credential.additionalBodyProperties);
if (parsedBody) {
options.body = parsedBody;
}
}
return options;
}
async discoverProtectedResourceMetadata(resourceUrl) {
this.validateOAuthUrlOrThrow(resourceUrl);
const url = new URL(resourceUrl);
const pathComponent = url.pathname.replace(/\/$/, '');
const discoveryUrls = pathComponent
? [
`${url.origin}/.well-known/oauth-protected-resource${pathComponent}`,
`${url.origin}/.well-known/oauth-protected-resource`,
]
: [
`${url.origin}/.well-known/oauth-protected-resource`,
];
for (const discoveryUrl of discoveryUrls) {
try {
this.validateOAuthUrlOrThrow(discoveryUrl);
const { data } = await axios_1.default.get(discoveryUrl, {
validateStatus: (status) => status === 200,
});
if (data &&
Array.isArray(data.authorization_servers) &&
data.authorization_servers.length > 0) {
return data;
}
}
catch (error) {
}
}
throw new bad_request_error_1.BadRequestError(`Failed to discover protected resource metadata. Tried: ${discoveryUrls.join(', ')}`);
}
selectGrantTypeAndAuthenticationMethod(grantTypes, tokenEndpointAuthMethods, codeChallengeMethods) {
if (grantTypes.includes('authorization_code')) {
if (codeChallengeMethods.includes('S256')) {
return { grantType: 'pkce' };
}
if (tokenEndpointAuthMethods.includes('client_secret_basic')) {
return { grantType: 'authorizationCode', authentication: 'header' };
}
if (tokenEndpointAuthMethods.includes('client_secret_post')) {
return { grantType: 'authorizationCode', authentication: 'body' };
}
}
if (grantTypes.includes('client_credentials')) {
if (tokenEndpointAuthMethods.includes('client_secret_basic')) {
return { grantType: 'clientCredentials', authentication: 'header' };
}
if (tokenEndpointAuthMethods.includes('client_secret_post')) {
return { grantType: 'clientCredentials', authentication: 'body' };
}
}
throw new bad_request_error_1.BadRequestError('No supported grant type and authentication method found');
}
mapGrantTypeAndAuthenticationMethod(grantType, authentication) {
if (grantType === 'pkce') {
return {
grant_types: ['authorization_code', 'refresh_token'],
token_endpoint_auth_method: 'none',
};
}
const tokenEndpointAuthMethod = authentication === 'header' ? 'client_secret_basic' : 'client_secret_post';
if (grantType === 'authorizationCode') {
return {
grant_types: ['authorization_code', 'refresh_token'],
token_endpoint_auth_method: tokenEndpointAuthMethod,
};
}
return {
grant_types: ['client_credentials'],
token_endpoint_auth_method: tokenEndpointAuthMethod,
};
}
async saveDynamicCredential(credential, oauthTokenData, authHeader, credentialResolverId, authMetadata = {}) {
const credentials = new n8n_core_1.Credentials(credential, credential.type, credential.data);
await credentials.updateData(oauthTokenData, ['csrfSecret']);
const credentialStoreMetadata = {
id: credential.id,
name: credential.name,
type: credential.type,
isResolvable: credential.isResolvable,
resolverId: credentialResolverId,
};
await this.dynamicCredentialsProxy.storeIfNeeded(credentialStoreMetadata, oauthTokenData, { version: 1, identity: authHeader, metadata: authMetadata }, await credentials.getData(), { credentialResolverId });
}
};
exports.OauthService = OauthService;
exports.OauthService = OauthService = OauthService_1 = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [backend_common_1.Logger,
credentials_helper_1.CredentialsHelper,
db_1.CredentialsRepository,
credentials_finder_service_1.CredentialsFinderService,
url_service_1.UrlService,
config_1.GlobalConfig,
external_hooks_1.ExternalHooks,
n8n_core_1.Cipher,
dynamic_credentials_proxy_1.DynamicCredentialsProxy])
], OauthService);
//# sourceMappingURL=oauth.service.js.map