first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.jwt",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development"],
|
||||
"alias": ["Token", "Key", "JSON", "Payload", "Sign", "Verify", "Decode"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/jwt/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.jwt/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import { formatPrivateKey } from '../../utils/utilities';
|
||||
import { parseJsonParameter } from '../Set/v2/helpers/utils';
|
||||
|
||||
const prettifyOperation = (operation: string) => {
|
||||
if (operation === 'sign') {
|
||||
return 'Sign a JWT';
|
||||
}
|
||||
|
||||
if (operation === 'decode') {
|
||||
return 'Decode a JWT';
|
||||
}
|
||||
|
||||
if (operation === 'verify') {
|
||||
return 'Verify a JWT';
|
||||
}
|
||||
|
||||
return operation;
|
||||
};
|
||||
|
||||
const getToken = (ctx: IExecuteFunctions, itemIndex = 0) => {
|
||||
const token = ctx.getNodeParameter('token', itemIndex) as string;
|
||||
|
||||
if (!token) {
|
||||
throw new NodeOperationError(ctx.getNode(), 'The JWT token was not provided', {
|
||||
itemIndex,
|
||||
description: "Be sure to add a valid JWT token to the 'Token' parameter",
|
||||
});
|
||||
}
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
export class Jwt implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'JWT',
|
||||
name: 'jwt',
|
||||
icon: 'file:jwt.svg',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
description: 'JWT',
|
||||
subtitle: `={{(${prettifyOperation})($parameter.operation)}}`,
|
||||
defaults: {
|
||||
name: 'JWT',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-credentials-name-unsuffixed
|
||||
name: 'jwtAuth',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Decode',
|
||||
value: 'decode',
|
||||
action: 'Decode a JWT',
|
||||
},
|
||||
{
|
||||
name: 'Sign',
|
||||
value: 'sign',
|
||||
action: 'Sign a JWT',
|
||||
},
|
||||
{
|
||||
name: 'Verify',
|
||||
value: 'verify',
|
||||
action: 'Verify a JWT',
|
||||
},
|
||||
],
|
||||
default: 'sign',
|
||||
},
|
||||
{
|
||||
displayName: 'Use JSON to Build Payload',
|
||||
name: 'useJson',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to use JSON to build the claims',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['sign'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Payload Claims',
|
||||
name: 'claims',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Claim',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Audience',
|
||||
name: 'audience',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. https://example.com',
|
||||
default: '',
|
||||
description: 'Identifies the recipients that the JWT is intended for',
|
||||
},
|
||||
{
|
||||
displayName: 'Expires In',
|
||||
name: 'expiresIn',
|
||||
type: 'number',
|
||||
placeholder: 'e.g. 3600',
|
||||
default: 3600,
|
||||
description: 'The lifetime of the token in seconds',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Issuer',
|
||||
name: 'issuer',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. https://example.com',
|
||||
default: '',
|
||||
description: 'Identifies the principal that issued the JWT',
|
||||
},
|
||||
{
|
||||
displayName: 'JWT ID',
|
||||
name: 'jwtid',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. 123456',
|
||||
default: '',
|
||||
description: 'Unique identifier for the JWT',
|
||||
},
|
||||
{
|
||||
displayName: 'Not Before',
|
||||
name: 'notBefore',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'The time before which the JWT must not be accepted for processing',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Subject',
|
||||
name: 'subject',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies the principal that is the subject of the JWT',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['sign'],
|
||||
useJson: [false],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Payload Claims (JSON)',
|
||||
name: 'claimsJson',
|
||||
type: 'json',
|
||||
description: 'Claims to add to the token in JSON format',
|
||||
default: '{\n "my_field_1": "value 1",\n "my_field_2": "value 2"\n}\n',
|
||||
validateType: 'object',
|
||||
ignoreValidationDuringExecution: true,
|
||||
typeOptions: {
|
||||
rows: 5,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['sign'],
|
||||
useJson: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Token',
|
||||
name: 'token',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
required: true,
|
||||
validateType: 'jwt',
|
||||
default: '',
|
||||
description: 'The token to verify or decode',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['verify', 'decode'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Return Additional Info',
|
||||
name: 'complete',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether to return the complete decoded token with information about the header and signature or just the payload',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['verify', 'decode'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore Expiration',
|
||||
name: 'ignoreExpiration',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to ignore the expiration of the token',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['verify'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore Not Before Claim',
|
||||
name: 'ignoreNotBefore',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to ignore the not before claim of the token',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['verify'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Clock Tolerance',
|
||||
name: 'clockTolerance',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description:
|
||||
'Number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['verify'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Key ID',
|
||||
name: 'kid',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. 123456',
|
||||
default: '',
|
||||
description:
|
||||
'The kid (key ID) claim is an optional header claim, used to specify the key for validating the signature',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['sign'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Override Algorithm',
|
||||
name: 'algorithm',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ES256',
|
||||
value: 'ES256',
|
||||
},
|
||||
{
|
||||
name: 'ES384',
|
||||
value: 'ES384',
|
||||
},
|
||||
{
|
||||
name: 'ES512',
|
||||
value: 'ES512',
|
||||
},
|
||||
{
|
||||
name: 'HS256',
|
||||
value: 'HS256',
|
||||
},
|
||||
{
|
||||
name: 'HS384',
|
||||
value: 'HS384',
|
||||
},
|
||||
{
|
||||
name: 'HS512',
|
||||
value: 'HS512',
|
||||
},
|
||||
{
|
||||
name: 'PS256',
|
||||
value: 'PS256',
|
||||
},
|
||||
{
|
||||
name: 'PS384',
|
||||
value: 'PS384',
|
||||
},
|
||||
{
|
||||
name: 'PS512',
|
||||
value: 'PS512',
|
||||
},
|
||||
{
|
||||
name: 'RS256',
|
||||
value: 'RS256',
|
||||
},
|
||||
{
|
||||
name: 'RS384',
|
||||
value: 'RS384',
|
||||
},
|
||||
{
|
||||
name: 'RS512',
|
||||
value: 'RS512',
|
||||
},
|
||||
],
|
||||
default: 'HS256',
|
||||
description:
|
||||
'The algorithm to use for signing or verifying the token, overrides algorithm in credentials',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/operation': ['sign', 'verify'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
|
||||
const credentials = await this.getCredentials<{
|
||||
keyType: 'passphrase' | 'pemKey';
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
secret: string;
|
||||
algorithm: jwt.Algorithm;
|
||||
}>('jwtAuth');
|
||||
|
||||
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||||
const options = this.getNodeParameter('options', itemIndex, {}) as {
|
||||
algorithm?: jwt.Algorithm;
|
||||
complete?: boolean;
|
||||
ignoreExpiration?: boolean;
|
||||
ignoreNotBefore?: boolean;
|
||||
clockTolerance?: number;
|
||||
kid?: string;
|
||||
};
|
||||
|
||||
try {
|
||||
if (operation === 'sign') {
|
||||
const useJson = this.getNodeParameter('useJson', itemIndex) as boolean;
|
||||
|
||||
let payload: IDataObject = {};
|
||||
|
||||
if (useJson) {
|
||||
payload = parseJsonParameter(
|
||||
this.getNodeParameter('claimsJson', itemIndex) as IDataObject,
|
||||
this.getNode(),
|
||||
itemIndex,
|
||||
);
|
||||
} else {
|
||||
payload = this.getNodeParameter('claims', itemIndex) as IDataObject;
|
||||
}
|
||||
|
||||
let secretOrPrivateKey;
|
||||
|
||||
if (credentials.keyType === 'passphrase') {
|
||||
secretOrPrivateKey = credentials.secret;
|
||||
} else {
|
||||
secretOrPrivateKey = formatPrivateKey(credentials.privateKey);
|
||||
}
|
||||
|
||||
const signingOptions: jwt.SignOptions = {
|
||||
algorithm: options.algorithm ?? credentials.algorithm,
|
||||
};
|
||||
if (options.kid) signingOptions.keyid = options.kid;
|
||||
|
||||
const token = jwt.sign(payload, secretOrPrivateKey, signingOptions);
|
||||
|
||||
returnData.push({
|
||||
json: { token },
|
||||
pairedItem: itemIndex,
|
||||
});
|
||||
}
|
||||
|
||||
if (operation === 'verify') {
|
||||
const token = getToken(this, itemIndex);
|
||||
|
||||
let secretOrPublicKey;
|
||||
|
||||
if (credentials.keyType === 'passphrase') {
|
||||
secretOrPublicKey = credentials.secret;
|
||||
} else {
|
||||
secretOrPublicKey = formatPrivateKey(credentials.publicKey, true);
|
||||
}
|
||||
|
||||
const { ignoreExpiration, ignoreNotBefore, clockTolerance, complete } = options;
|
||||
|
||||
const data = jwt.verify(token, secretOrPublicKey, {
|
||||
algorithms: [options.algorithm ?? credentials.algorithm],
|
||||
ignoreExpiration,
|
||||
ignoreNotBefore,
|
||||
clockTolerance,
|
||||
complete,
|
||||
});
|
||||
|
||||
const json = options.complete && data ? (data as IDataObject) : { payload: data };
|
||||
|
||||
returnData.push({
|
||||
json,
|
||||
pairedItem: itemIndex,
|
||||
});
|
||||
}
|
||||
|
||||
if (operation === 'decode') {
|
||||
const token = getToken(this, itemIndex);
|
||||
|
||||
const data = jwt.decode(token, { complete: options.complete });
|
||||
|
||||
const json = options.complete && data ? (data as IDataObject) : { payload: data };
|
||||
|
||||
returnData.push({
|
||||
json,
|
||||
pairedItem: itemIndex,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message === 'invalid signature') {
|
||||
error = new NodeOperationError(this.getNode(), "The JWT token can't be verified", {
|
||||
itemIndex,
|
||||
description:
|
||||
'Be sure that the provided JWT token is correctly encoded and matches the selected credentials',
|
||||
});
|
||||
}
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({
|
||||
json: this.getInputData(itemIndex)[0].json,
|
||||
error,
|
||||
pairedItem: itemIndex,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (error.context) {
|
||||
error.context.itemIndex = itemIndex;
|
||||
throw error;
|
||||
}
|
||||
throw new NodeOperationError(this.getNode(), error, {
|
||||
itemIndex,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="200px"
|
||||
height="200px"
|
||||
viewBox="0 0 200 200"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
|
||||
<title
|
||||
id="title1">Group</title>
|
||||
<desc
|
||||
id="desc1">Created with Sketch.</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter11"
|
||||
x="-0.18346753"
|
||||
y="-0.076523014"
|
||||
width="1.3669351"
|
||||
height="1.153046">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.2230926"
|
||||
id="feGaussianBlur11" />
|
||||
</filter>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter12"
|
||||
x="-0.18346753"
|
||||
y="-0.076523014"
|
||||
width="1.3669351"
|
||||
height="1.153046">
|
||||
<feGaussianBlur
|
||||
stdDeviation="1.2230926"
|
||||
id="feGaussianBlur12" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
id="layer1" />
|
||||
<g
|
||||
transform="translate(57.626456,48.948311)"
|
||||
id="Shape-6">
|
||||
<g
|
||||
id="g12"
|
||||
transform="matrix(1.8791546,0,0,1.8791546,-51.584186,-42.862227)">
|
||||
<path
|
||||
d="M 42.223544,27.435493 V -0.303311 H 58.223226 V 27.435493 L 50.223385,38.05668 Z"
|
||||
fill="#ffffff"
|
||||
id="path11"
|
||||
style="fill:#ececec;stroke-width:1.04876;filter:url(#filter12)" />
|
||||
<path
|
||||
d="M 57.5,26.9 V 0 h -15 V 26.9 L 50,37.2 Z"
|
||||
fill="#ffffff"
|
||||
id="path1-7" />
|
||||
<path
|
||||
d="M 42.223544,72.517876 V 100.25668 H 58.223226 V 72.517876 L 50.223385,61.896689 Z"
|
||||
fill="#ffffff"
|
||||
id="path10"
|
||||
style="fill:#ececec;stroke-width:1.04876;filter:url(#filter11)" />
|
||||
<path
|
||||
d="m 42.623319,73.156936 v 26.900004 h 15 V 73.156936 l -7.5,-10.3 z"
|
||||
fill="#ffffff"
|
||||
id="path2-5" />
|
||||
<path
|
||||
d="M 57.5,73.1 73.3,94.9 85.5,86 69.6,64.3 57.5,60.3 Z"
|
||||
fill="#00f2e6"
|
||||
id="path3-3" />
|
||||
<path
|
||||
d="M 42.5,26.9 26.7,5.1 14.5,14 l 15.9,21.7 12.1,4 z"
|
||||
fill="#00f2e6"
|
||||
id="path4-5" />
|
||||
<path
|
||||
d="M 30.4,35.7 4.8,27.4 0.1,41.7 25.7,50 37.9,46.1 Z"
|
||||
fill="#00b9f1"
|
||||
id="path5-6" />
|
||||
<path
|
||||
d="M 62.1,53.9 69.6,64.3 95.2,72.6 99.9,58.3 74.3,50 Z"
|
||||
fill="#00b9f1"
|
||||
id="path6-2" />
|
||||
<path
|
||||
d="M 74.3,50 99.9,41.7 95.2,27.4 69.6,35.7 62.1,46.1 Z"
|
||||
fill="#d63aff"
|
||||
id="path7-9" />
|
||||
<path
|
||||
d="M 25.7,50 0.1,58.3 4.8,72.6 30.4,64.3 37.9,53.9 Z"
|
||||
fill="#d63aff"
|
||||
id="path8-1" />
|
||||
<path
|
||||
d="M 30.4,64.3 14.5,86 26.7,94.9 42.5,73.1 V 60.3 Z"
|
||||
fill="#fb015b"
|
||||
id="path9-2" />
|
||||
<path
|
||||
d="M 69.6,35.7 85.5,14 73.3,5.1 57.5,26.9 v 12.8 z"
|
||||
fill="#fb015b"
|
||||
id="path10-7" />
|
||||
</g>
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>Group</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,13 @@
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
|
||||
const credentials = {
|
||||
jwtAuth: {
|
||||
keyType: 'passphrase',
|
||||
secret: 'baz',
|
||||
algorithm: 'HS256',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Test Jwt Node', () => {
|
||||
new NodeTestHarness().setupTests({ credentials });
|
||||
});
|
||||
@@ -0,0 +1,568 @@
|
||||
{
|
||||
"name": "JWT Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "66c858d2-822e-4177-a379-d5e2aef9f6da",
|
||||
"name": "When clicking ‘Execute workflow’",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [-260, 840]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"claims": {
|
||||
"audience": "test",
|
||||
"issuer": "test",
|
||||
"jwtid": "123",
|
||||
"subject": "test"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "675b43b8-f079-4bcf-8ea2-52c3c60a3a42",
|
||||
"name": "Sign with claims",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [120, 400],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"useJson": true,
|
||||
"options": {}
|
||||
},
|
||||
"id": "c24f27d7-48fc-47c3-864d-f05456abe7c2",
|
||||
"name": "Sign with JSON Payload",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [120, 840],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "verify",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {
|
||||
"complete": true,
|
||||
"ignoreExpiration": true,
|
||||
"ignoreNotBefore": true
|
||||
}
|
||||
},
|
||||
"id": "ff74f160-8f43-4cd1-a089-4698713ea12d",
|
||||
"name": "Verify1",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 480],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "decode",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "9fcb58bd-f28b-4106-a3ab-ad2a64b6b0f5",
|
||||
"name": "Decode2",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 740],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "decode",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "913e5542-12a0-4a48-9646-4fba648ec95b",
|
||||
"name": "Decode1",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 300],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "verify",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "c888549a-b1fb-47e8-bf90-07cec2b32483",
|
||||
"name": "Verify2",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 920],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"claims": {
|
||||
"audience": "test",
|
||||
"issuer": "test",
|
||||
"jwtid": "123",
|
||||
"subject": "test"
|
||||
},
|
||||
"options": {
|
||||
"kid": "custom-kid"
|
||||
}
|
||||
},
|
||||
"id": "3aedaf15-026d-4874-99c1-ab5940f18c73",
|
||||
"name": "Sign with kid",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [120, 1280],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "1289f607-d46f-45f5-953a-1492f3b50bbd",
|
||||
"name": "payload.audience",
|
||||
"value": "={{ $json.payload.audience }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "e32ae71b-62ca-45e5-8351-2fd9ab7451ef",
|
||||
"name": "payload.jwtid",
|
||||
"value": "={{ $json.payload.jwtid }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "9d8471ca-b918-4450-b2e3-735799399d39",
|
||||
"name": "Decode1 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "3ff845d5-9c2c-4744-bc33-a7318b4741fc",
|
||||
"name": "payload.audience",
|
||||
"value": "={{ $json.payload.audience }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "d1206579-634e-472a-9190-a176cf2477a1",
|
||||
"name": "payload.jwtid",
|
||||
"value": "={{ $json.payload.jwtid }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "dd0aa97d-a485-4cc3-a8af-55e73fb21716",
|
||||
"name": "Verify1 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 480]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "fe90f817-1b89-409c-992c-e42070fc67bf",
|
||||
"name": "payload.my_field_1",
|
||||
"value": "={{ $json.payload.my_field_1 }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "1b80e8b3-3004-4959-8c6c-0d36176579ea",
|
||||
"name": "payload.my_field_2",
|
||||
"value": "={{ $json.payload.my_field_2 }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "f47b9996-ce95-4b72-a9ae-5e5a616ff982",
|
||||
"name": "Decode2 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 740]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "46ed5c03-d41a-4387-988e-2ed3821f32d4",
|
||||
"name": "payload.my_field_1",
|
||||
"value": "={{ $json.payload.my_field_1 }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "0007786e-3f93-4146-8e10-32ab8e088b81",
|
||||
"name": "payload.my_field_2",
|
||||
"value": "={{ $json.payload.my_field_2 }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "5ba29142-407f-4e39-a3ed-28dff742070a",
|
||||
"name": "Verify2 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 920]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "decode",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {
|
||||
"complete": true
|
||||
}
|
||||
},
|
||||
"id": "ab038c41-45eb-4679-a71d-fc3c60797983",
|
||||
"name": "Decode3",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 1180],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "verify",
|
||||
"token": "={{ $json.token }}",
|
||||
"options": {
|
||||
"complete": true
|
||||
}
|
||||
},
|
||||
"id": "3442124e-af80-4cb0-bae0-4716f5a367af",
|
||||
"name": "Verify3",
|
||||
"type": "n8n-nodes-base.jwt",
|
||||
"typeVersion": 1,
|
||||
"position": [380, 1360],
|
||||
"credentials": {
|
||||
"jwtAuth": {
|
||||
"id": "kDnfvqrCBJvtlX3o",
|
||||
"name": "JWT Auth account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "1289f607-d46f-45f5-953a-1492f3b50bbd",
|
||||
"name": "payload.audience",
|
||||
"value": "={{ $json.payload.audience }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "e32ae71b-62ca-45e5-8351-2fd9ab7451ef",
|
||||
"name": "payload.jwtid",
|
||||
"value": "={{ $json.payload.jwtid }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "99695f75-e483-4e12-8316-b669f73a7dfe",
|
||||
"name": "header.kid",
|
||||
"value": "={{ $json.header.kid }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "28786e3b-9f7b-42e1-b5d2-b5484870b51a",
|
||||
"name": "Decode3 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 1180]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "3ff845d5-9c2c-4744-bc33-a7318b4741fc",
|
||||
"name": "payload.audience",
|
||||
"value": "={{ $json.payload.audience }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "d1206579-634e-472a-9190-a176cf2477a1",
|
||||
"name": "payload.jwtid",
|
||||
"value": "={{ $json.payload.jwtid }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "1d39fe9e-d513-4bcf-8f2e-3bce3b45e37b",
|
||||
"name": "header.kid",
|
||||
"value": "={{ $json.header.kid }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "3a4dbfb1-4d3c-479c-a848-a8c3e148b4ab",
|
||||
"name": "Verify3 Output",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.3,
|
||||
"position": [580, 1360]
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"Decode1 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"audience": "test",
|
||||
"jwtid": "123"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Verify1 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"audience": "test",
|
||||
"jwtid": "123"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Decode2 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"my_field_1": "value 1",
|
||||
"my_field_2": "value 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Verify2 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"my_field_1": "value 1",
|
||||
"my_field_2": "value 2"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Decode3 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"audience": "test",
|
||||
"jwtid": "123"
|
||||
},
|
||||
"header": {
|
||||
"kid": "custom-kid"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Verify3 Output": [
|
||||
{
|
||||
"json": {
|
||||
"payload": {
|
||||
"audience": "test",
|
||||
"jwtid": "123"
|
||||
},
|
||||
"header": {
|
||||
"kid": "custom-kid"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking ‘Execute workflow’": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Sign with claims",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Sign with JSON Payload",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Sign with kid",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sign with claims": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Verify1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sign with JSON Payload": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode2",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Verify2",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Verify1": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Verify1 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Decode2": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode2 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Decode1": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode1 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Verify2": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Verify2 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sign with kid": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode3",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Verify3",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Decode3": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Decode3 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Verify3": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Verify3 Output",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user