n8n
Version:
n8n Workflow Automation Tool
154 lines • 7.38 kB
JavaScript
"use strict";
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 __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenExchangeController = void 0;
const constants_1 = require("@n8n/constants");
const decorators_1 = require("@n8n/decorators");
const di_1 = require("@n8n/di");
const n8n_core_1 = require("n8n-core");
const zod_1 = require("zod");
const auth_error_1 = require("../../../errors/response-errors/auth.error");
const bad_request_error_1 = require("../../../errors/response-errors/bad-request.error");
const event_service_1 = require("../../../events/event.service");
const token_exchange_service_1 = require("../services/token-exchange.service");
const token_exchange_config_1 = require("../token-exchange.config");
const token_exchange_errors_1 = require("../token-exchange.errors");
const token_exchange_schemas_1 = require("../token-exchange.schemas");
const token_exchange_types_1 = require("../token-exchange.types");
const configService = di_1.Container.get(token_exchange_config_1.TokenExchangeConfig);
let TokenExchangeController = class TokenExchangeController {
constructor() {
this.config = di_1.Container.get(token_exchange_config_1.TokenExchangeConfig);
this.errorReporter = di_1.Container.get(n8n_core_1.ErrorReporter);
this.eventService = di_1.Container.get(event_service_1.EventService);
this.tokenExchangeService = di_1.Container.get(token_exchange_service_1.TokenExchangeService);
}
async exchangeToken(req, res) {
if (!this.config.enabled) {
res.status(501).json({
error: 'server_error',
error_description: 'Token exchange is not enabled on this instance',
});
return;
}
const clientIp = req.ip ?? 'unknown';
const { data: grantTypeData } = zod_1.z
.object({ grant_type: zod_1.z.string().optional() })
.safeParse(req.body);
if (grantTypeData?.grant_type !== token_exchange_schemas_1.TOKEN_EXCHANGE_GRANT_TYPE) {
res.status(400).json({
error: 'unsupported_grant_type',
error_description: `grant_type must be "${token_exchange_schemas_1.TOKEN_EXCHANGE_GRANT_TYPE}"`,
});
return;
}
const parsed = token_exchange_schemas_1.TokenExchangeRequestSchema.safeParse(req.body);
if (!parsed.success) {
const firstIssue = parsed.error.issues[0];
res.status(400).json({
error: 'invalid_request',
error_description: firstIssue?.message ?? 'Invalid request parameters',
});
return;
}
try {
const result = await this.tokenExchangeService.exchange(parsed.data);
this.eventService.emit('token-exchange-succeeded', {
subject: result.subject,
actor: result.actor,
scopes: parsed.data.scope,
resource: parsed.data.resource,
grantType: parsed.data.grant_type,
clientIp,
issuer: result.issuer,
});
res.json({
access_token: result.accessToken,
token_type: 'Bearer',
expires_in: result.expiresIn,
issued_token_type: 'urn:ietf:params:oauth:token-type:access_token',
});
}
catch (error) {
if (error instanceof auth_error_1.AuthError) {
this.eventService.emit('token-exchange-failed', {
subject: '',
failureReason: error instanceof token_exchange_errors_1.TokenExchangeAuthError
? error.reason
: token_exchange_types_1.TokenExchangeFailureReason.Other,
grantType: parsed.data.grant_type,
clientIp,
});
res.status(400).json({
error: 'invalid_grant',
error_description: 'Token exchange failed',
});
return;
}
if (error instanceof bad_request_error_1.BadRequestError) {
this.eventService.emit('token-exchange-failed', {
subject: '',
failureReason: error instanceof token_exchange_errors_1.TokenExchangeRequestError
? error.reason
: token_exchange_types_1.TokenExchangeFailureReason.InvalidFormat,
grantType: parsed.data.grant_type,
clientIp,
});
res.status(400).json({
error: 'invalid_request',
error_description: error.message,
});
return;
}
if (error instanceof zod_1.ZodError) {
this.eventService.emit('token-exchange-failed', {
subject: '',
failureReason: token_exchange_types_1.TokenExchangeFailureReason.InvalidClaims,
grantType: parsed.data.grant_type,
clientIp,
});
res.status(400).json({
error: 'invalid_request',
error_description: 'Token claims validation failed',
});
return;
}
this.errorReporter.error(error instanceof Error ? error : new Error(String(error)));
this.eventService.emit('token-exchange-failed', {
subject: '',
failureReason: token_exchange_types_1.TokenExchangeFailureReason.InternalError,
grantType: parsed.data.grant_type,
clientIp,
});
res.status(500).json({
error: 'server_error',
error_description: 'An unexpected error occurred during token exchange',
});
}
}
};
exports.TokenExchangeController = TokenExchangeController;
__decorate([
(0, decorators_1.Post)('/token', {
skipAuth: true,
ipRateLimit: {
limit: configService.rateLimitTokenExchange,
windowMs: 1 * constants_1.Time.minutes.toMilliseconds,
},
}),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], TokenExchangeController.prototype, "exchangeToken", null);
exports.TokenExchangeController = TokenExchangeController = __decorate([
(0, decorators_1.RestController)('/auth/oauth')
], TokenExchangeController);
//# sourceMappingURL=token-exchange.controller.js.map