Skip to content

Commit a656bb5

Browse files
committed
1. **Use Serverless Workflow 1.x syntax** with proper YAML format and dsl: 1.0.0-alpha1
2. **Replace the recursive call** with a proper `set` task using jq expressions 3. **Implement JWT decoding with jq**: The function now uses `split(".")[1] | @base64d | fromjson` to decode the JWT payload 4. **Add optional claim extraction** via `claimPath` parameter using jq path navigation Signed-off-by: Ishan Jogi <ijogi@redhat.com>
1 parent c496315 commit a656bb5

File tree

2 files changed

+123
-171
lines changed

2 files changed

+123
-171
lines changed

functions/jwt-parser/1.0.0/README.md

Lines changed: 106 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,142 @@
11
# JWT Parser Function
22

3-
The JWT Parser function allows SonataFlow workflows to parse and extract information from JWT (JSON Web Token) tokens. This is particularly useful for accessing user information and claims from authentication tokens passed in workflow headers.
3+
The JWT Parser function allows Serverless Workflow 1.x workflows to parse and extract information from JWT (JSON Web Token) tokens using jq expressions. This function decodes the JWT payload and optionally extracts specific claims.
44

55
## Overview
66

7-
This function provides three main operations:
8-
- **parse**: Extract the complete JWT payload as a JSON object
9-
- **extractUser**: Extract standard user information from JWT claims (sub, preferred_username, email, etc.)
10-
- **extractClaim**: Extract a specific claim by name
7+
This function uses a `set` task with jq expressions to:
8+
- Decode JWT tokens (with or without "Bearer " prefix)
9+
- Extract the complete JWT payload as JSON
10+
- Optionally extract specific claims using jq paths
1111

1212
## Usage
1313

14-
### Basic JWT Parsing
15-
16-
```json
17-
{
18-
"functions": [
19-
{
20-
"name": "parseJWT",
21-
"type": "custom",
22-
"operation": "jwt-parser"
23-
}
24-
],
25-
"states": [
26-
{
27-
"name": "parseToken",
28-
"type": "operation",
29-
"actions": [
30-
{
31-
"name": "parseAction",
32-
"functionRef": {
33-
"refName": "parseJWT",
34-
"arguments": {
35-
"token": "${ $WORKFLOW.headers.\"Authorization\" }",
36-
"operation": "parse"
37-
}
38-
}
39-
}
40-
]
41-
}
42-
]
43-
}
14+
### Basic JWT Parsing (Complete Payload)
15+
16+
```yaml
17+
document:
18+
dsl: 1.0.0-alpha1
19+
namespace: examples
20+
name: jwt-parsing
21+
version: 1.0.0
22+
do:
23+
- parseToken:
24+
use: jwt-parser
25+
with:
26+
token: ${ .headers.authorization }
4427
```
4528
46-
### Extract User Information
47-
48-
```json
49-
{
50-
"functions": [
51-
{
52-
"name": "extractUser",
53-
"type": "custom",
54-
"operation": "jwt-parser:extractUser"
55-
}
56-
],
57-
"states": [
58-
{
59-
"name": "extractUserName",
60-
"type": "operation",
61-
"actions": [
62-
{
63-
"name": "extractUserAction",
64-
"functionRef": {
65-
"refName": "extractUser",
66-
"arguments": {
67-
"token": "${ $WORKFLOW.headers.\"X-Authorization-acme_financial_auth\" }"
68-
}
69-
}
70-
}
71-
],
72-
"stateDataFilter": {
73-
"output": "${ { user: .result.preferred_username } }"
74-
}
75-
}
76-
]
77-
}
29+
### Extract Specific Claims
30+
31+
```yaml
32+
document:
33+
dsl: 1.0.0-alpha1
34+
namespace: examples
35+
name: jwt-user-extraction
36+
version: 1.0.0
37+
do:
38+
- extractUsername:
39+
use: jwt-parser
40+
with:
41+
token: ${ .headers.authorization }
42+
claimPath: ".preferred_username"
43+
- extractEmail:
44+
use: jwt-parser
45+
with:
46+
token: ${ .headers.authorization }
47+
claimPath: ".email"
7848
```
7949
80-
### Extract Specific Claim
81-
82-
```json
83-
{
84-
"functions": [
85-
{
86-
"name": "extractClaim",
87-
"type": "custom",
88-
"operation": "jwt-parser:extractClaim"
89-
}
90-
],
91-
"states": [
92-
{
93-
"name": "extractRole",
94-
"type": "operation",
95-
"actions": [
96-
{
97-
"name": "extractRoleAction",
98-
"functionRef": {
99-
"refName": "extractClaim",
100-
"arguments": {
101-
"token": "${ $WORKFLOW.headers.\"Authorization\" }",
102-
"claim": "role"
103-
}
104-
}
105-
}
106-
]
107-
}
108-
]
109-
}
50+
### Multiple Claim Extraction
51+
52+
```yaml
53+
document:
54+
dsl: 1.0.0-alpha1
55+
namespace: examples
56+
name: jwt-multi-claims
57+
version: 1.0.0
58+
do:
59+
- getUserInfo:
60+
use: jwt-parser
61+
with:
62+
token: ${ .headers["x-authorization-acme_financial_auth"] }
63+
- processUserData:
64+
use: set
65+
set:
66+
username: ${ .result.preferred_username }
67+
email: ${ .result.email }
68+
userId: ${ .result.sub }
69+
message: ${ "Welcome " + .username + "! Your request has been processed." }
11070
```
11171
112-
## Complete Example
113-
114-
Here's a complete workflow that demonstrates JWT parsing for user personalization:
115-
116-
```json
117-
{
118-
"id": "jwt_example",
119-
"version": "1.0",
120-
"name": "JWT Token Processing Example",
121-
"start": "extractUser",
122-
"functions": [
123-
{
124-
"name": "extractUser",
125-
"type": "custom",
126-
"operation": "jwt-parser:extractUser"
127-
}
128-
],
129-
"states": [
130-
{
131-
"name": "extractUser",
132-
"type": "operation",
133-
"actions": [
134-
{
135-
"name": "extractUserAction",
136-
"functionRef": {
137-
"refName": "extractUser",
138-
"arguments": {
139-
"token": "${ $WORKFLOW.headers.\"X-Authorization-acme_financial_auth\" }"
140-
}
141-
}
142-
}
143-
],
144-
"stateDataFilter": {
145-
"output": "${ { user: .result.preferred_username } }"
146-
},
147-
"transition": "personalizedResponse"
148-
},
149-
{
150-
"name": "personalizedResponse",
151-
"type": "inject",
152-
"data": {
153-
"approved": true
154-
},
155-
"stateDataFilter": {
156-
"output": "${ { message: \"Congrats \\(.user)! Your request has been approved!\", approved } }"
157-
},
158-
"end": true
159-
}
160-
]
161-
}
72+
## Complete Example - Loan Approval with User Personalization
73+
74+
```yaml
75+
document:
76+
dsl: 1.0.0-alpha1
77+
namespace: examples
78+
name: loan-approval-jwt
79+
version: 1.0.0
80+
do:
81+
- extractUserInfo:
82+
use: jwt-parser
83+
with:
84+
token: ${ .headers["x-authorization-acme_financial_auth"] }
85+
- processLoanApproval:
86+
use: set
87+
set:
88+
user: ${ .result.preferred_username }
89+
userId: ${ .result.sub }
90+
email: ${ .result.email }
91+
loanApproved: true
92+
message: ${ "Congrats " + .user + "! Your loan has been approved!" }
16293
```
16394
16495
## Parameters
16596
16697
| Parameter | Type | Required | Description |
16798
|-----------|------|----------|-------------|
168-
| `token` | string | Yes | The JWT token to parse (Bearer prefix will be automatically removed) |
169-
| `operation` | string | No | Operation to perform: "parse", "extractUser", or "extractClaim" (default: "parse") |
170-
| `claim` | string | No | Name of specific claim to extract (required when operation is "extractClaim") |
99+
| `token` | string | Yes | The JWT token to parse (Bearer prefix will be automatically handled) |
100+
| `claimPath` | string | No | jq path to extract specific claim (e.g., ".sub", ".preferred_username", ".email") |
171101

172102
## Output
173103

174-
The function returns a JSON object containing:
175-
- For `parse`: Complete JWT payload
176-
- For `extractUser`: Standard user claims (sub, preferred_username, email, name, etc.)
177-
- For `extractClaim`: The specific claim value
104+
The function returns:
105+
- `claims`: The complete decoded JWT payload as JSON object
106+
- `result`: Either the complete payload (if no claimPath) or the specific claim value (if claimPath provided)
178107

179108
## Token Format Support
180109

181110
The function supports JWT tokens in various formats:
182111
- Raw JWT token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`
183112
- Bearer token: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`
184113

114+
## jq Expression Details
115+
116+
The function uses these jq expressions:
117+
- **Token cleanup**: Removes "Bearer " prefix if present
118+
- **JWT decoding**: Splits token, extracts payload (part 1), base64 decodes, and parses JSON
119+
- **Claim extraction**: Uses jq path navigation to extract specific claims
120+
121+
## Common Claim Paths
122+
123+
- `.sub` - Subject (user ID)
124+
- `.preferred_username` - Username
125+
- `.email` - Email address
126+
- `.name` - Full name
127+
- `.given_name` - First name
128+
- `.family_name` - Last name
129+
- `.roles` - User roles array
130+
- `.exp` - Expiration timestamp
131+
- `.iat` - Issued at timestamp
132+
185133
## Error Handling
186134

187-
The function will fail if:
135+
The jq expressions will fail if:
188136
- Token is null or empty
189-
- Token format is invalid
190-
- Required claim parameter is missing for extractClaim operation
137+
- Token format is invalid (not 3 parts separated by dots)
138+
- JWT payload is not valid base64 or JSON
139+
- Specified claimPath does not exist
191140

192141
## Security Note
193142

functions/jwt-parser/1.0.0/function.yaml

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,27 @@ input:
77
type: string
88
title: JWT Token
99
description: The JWT token to parse (can include "Bearer " prefix)
10-
operation:
10+
claimPath:
1111
type: string
12-
enum: [ "parse", "extractUser", "extractClaim" ]
13-
default: "parse"
14-
title: Operation
15-
description: The operation to perform on the JWT token
16-
claim:
17-
type: string
18-
title: Claim Name
19-
description: The name of the specific claim to extract (required for extractClaim operation)
12+
title: Claim Path
13+
description: Optional jq path to extract specific claim (e.g., ".sub", ".preferred_username", ".email")
2014
required: [ token ]
2115
output:
2216
schema:
2317
document:
2418
type: object
2519
description: The parsed JWT payload or extracted claim as a JSON object
26-
call: jwt-parser
27-
with:
28-
operation: ${ .operation }
29-
token: ${ .token }
30-
claim: ${ .claim }
20+
use: set
21+
set:
22+
claims: >-
23+
if (.token | startswith("Bearer ")) then
24+
(.token[7:] | split(".")[1] | @base64d | fromjson)
25+
else
26+
(.token | split(".")[1] | @base64d | fromjson)
27+
end
28+
result: >-
29+
if .claimPath then
30+
.claims | getpath(.claimPath | split(".") | map(select(. != "")))
31+
else
32+
.claims
33+
end

0 commit comments

Comments
 (0)