Skip to content

Commit 579a18c

Browse files
authored
crypto: add optional headers param to JWT signing methods
1 parent 6e3013e commit 579a18c

File tree

3 files changed

+271
-0
lines changed

3 files changed

+271
-0
lines changed

docs/modules/guides/pages/bloblang/methods.adoc

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4183,6 +4183,7 @@ Introduced in version v4.20.0.
41834183
==== Parameters
41844184
41854185
*`signing_secret`* <string> The secret to use for signing the token.
4186+
*`headers`* <(optional) unknown> Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
41864187
41874188
==== Examples
41884189
@@ -4196,6 +4197,15 @@ root.signed = this.claims.sign_jwt_es256("""-----BEGIN EC PRIVATE KEY-----
41964197
# Out: {"signed":"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm1vb2QiOiJEaXNkYWluZnVsIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.-8LrOdkEiv_44ADWW08lpbq41ZmHCel58NMORPq1q4Dyw0zFhqDVLrRoSvCvuyyvgXAFb9IHfR-9MlJ_2ShA9A"}
41974198
```
41984199
4200+
```coffeescript
4201+
root.signed = this.claims.sign_jwt_es256(signing_secret: """-----BEGIN EC PRIVATE KEY-----
4202+
... signature data ...
4203+
-----END EC PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4204+
4205+
# In: {"claims":{"sub":"user123"}}
4206+
# Out: {"signed":"<signed JWT token>"}
4207+
```
4208+
41994209
=== `sign_jwt_es384`
42004210
42014211
Hash and sign an object representing JSON Web Token (JWT) claims using ES384.
@@ -4206,6 +4216,7 @@ Introduced in version v4.20.0.
42064216
==== Parameters
42074217
42084218
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4219+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
42094220
42104221
==== Examples
42114222
@@ -4219,6 +4230,15 @@ root.signed = this.claims.sign_jwt_es384("""-----BEGIN EC PRIVATE KEY-----
42194230
# Out: {"signed":"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.8FmTKH08dl7dyxrNu0rmvhegiIBCy-O9cddGco2e9lpZtgv5mS5qHgPkgBC5eRw1d7SRJsHwHZeehzdqT5Ba7aZJIhz9ds0sn37YQ60L7jT0j2gxCzccrt4kECHnUnLw"}
42204231
```
42214232
4233+
```coffeescript
4234+
root.signed = this.claims.sign_jwt_es384(signing_secret: """-----BEGIN EC PRIVATE KEY-----
4235+
... signature data ...
4236+
-----END EC PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4237+
4238+
# In: {"claims":{"sub":"user123"}}
4239+
# Out: {"signed":"<signed JWT token>"}
4240+
```
4241+
42224242
=== `sign_jwt_es512`
42234243
42244244
Hash and sign an object representing JSON Web Token (JWT) claims using ES512.
@@ -4229,6 +4249,7 @@ Introduced in version v4.20.0.
42294249
==== Parameters
42304250
42314251
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4252+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
42324253
42334254
==== Examples
42344255
@@ -4242,6 +4263,15 @@ root.signed = this.claims.sign_jwt_es512("""-----BEGIN EC PRIVATE KEY-----
42424263
# Out: {"signed":"eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.AQbEWymoRZxDJEJtKSFFG2k2VbDCTYSuBwAZyMqexCspr3If8aERTVGif8HXG3S7TzMBCCzxkcKr3eIU441l3DlpAMNfQbkcOlBqMvNBn-CX481WyKf3K5rFHQ-6wRonz05aIsWAxCDvAozI_9J0OWllxdQ2MBAuTPbPJ38OqXsYkCQs"}
42434264
```
42444265
4266+
```coffeescript
4267+
root.signed = this.claims.sign_jwt_es512(signing_secret: """-----BEGIN EC PRIVATE KEY-----
4268+
... signature data ...
4269+
-----END EC PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4270+
4271+
# In: {"claims":{"sub":"user123"}}
4272+
# Out: {"signed":"<signed JWT token>"}
4273+
```
4274+
42454275
=== `sign_jwt_hs256`
42464276
42474277
Hash and sign an object representing JSON Web Token (JWT) claims using HS256.
@@ -4252,6 +4282,7 @@ Introduced in version v4.12.0.
42524282
==== Parameters
42534283
42544284
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4285+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
42554286
42564287
==== Examples
42574288
@@ -4263,6 +4294,13 @@ root.signed = this.claims.sign_jwt_hs256("""dont-tell-anyone""")
42634294
# Out: {"signed":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.hUl-nngPMY_3h9vveWJUPsCcO5PeL6k9hWLnMYeFbFQ"}
42644295
```
42654296
4297+
```coffeescript
4298+
root.signed = this.claims.sign_jwt_hs256(signing_secret: """dont-tell-anyone""", headers: {"kid": "my-key", "x": "y"})
4299+
4300+
# In: {"claims":{"sub":"user123"}}
4301+
# Out: {"signed":"<signed JWT token>"}
4302+
```
4303+
42664304
=== `sign_jwt_hs384`
42674305
42684306
Hash and sign an object representing JSON Web Token (JWT) claims using HS384.
@@ -4273,6 +4311,7 @@ Introduced in version v4.12.0.
42734311
==== Parameters
42744312
42754313
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4314+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
42764315
42774316
==== Examples
42784317
@@ -4284,6 +4323,13 @@ root.signed = this.claims.sign_jwt_hs384("""dont-tell-anyone""")
42844323
# Out: {"signed":"eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.zGYLr83aToon1efUNq-hw7XgT20lPvZb8sYei8x6S6mpHwb433SJdXJXx0Oio8AZ"}
42854324
```
42864325
4326+
```coffeescript
4327+
root.signed = this.claims.sign_jwt_hs384(signing_secret: """dont-tell-anyone""", headers: {"kid": "my-key", "x": "y"})
4328+
4329+
# In: {"claims":{"sub":"user123"}}
4330+
# Out: {"signed":"<signed JWT token>"}
4331+
```
4332+
42874333
=== `sign_jwt_hs512`
42884334
42894335
Hash and sign an object representing JSON Web Token (JWT) claims using HS512.
@@ -4294,6 +4340,7 @@ Introduced in version v4.12.0.
42944340
==== Parameters
42954341
42964342
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4343+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
42974344
42984345
==== Examples
42994346
@@ -4305,6 +4352,13 @@ root.signed = this.claims.sign_jwt_hs512("""dont-tell-anyone""")
43054352
# Out: {"signed":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.zBNR9o_6EDwXXKkpKLNJhG26j8Dc-mV-YahBwmEdCrmiWt5les8I9rgmNlWIowpq6Yxs4kLNAdFhqoRz3NXT3w"}
43064353
```
43074354
4355+
```coffeescript
4356+
root.signed = this.claims.sign_jwt_hs512(signing_secret: """dont-tell-anyone""", headers: {"kid": "my-key", "x": "y"})
4357+
4358+
# In: {"claims":{"sub":"user123"}}
4359+
# Out: {"signed":"<signed JWT token>"}
4360+
```
4361+
43084362
=== `sign_jwt_rs256`
43094363
43104364
Hash and sign an object representing JSON Web Token (JWT) claims using RS256.
@@ -4315,6 +4369,7 @@ Introduced in version v4.18.0.
43154369
==== Parameters
43164370
43174371
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4372+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
43184373
43194374
==== Examples
43204375
@@ -4328,6 +4383,15 @@ root.signed = this.claims.sign_jwt_rs256("""-----BEGIN RSA PRIVATE KEY-----
43284383
# Out: {"signed":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm1vb2QiOiJEaXNkYWluZnVsIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.b0lH3jEupZZ4zoaly4Y_GCvu94HH6UKdKY96zfGNsIkPZpQLHIkZ7jMWlLlNOAd8qXlsBGP_i8H2qCKI4zlWJBGyPZgxXDzNRPVrTDfFpn4t4nBcA1WK2-ntXP3ehQxsaHcQU8Z_nsogId7Pme5iJRnoHWEnWtbwz5DLSXL3ZZNnRdrHM9MdI7QSDz9mojKDCaMpGN9sG7Xl-tGdBp1XzXuUOzG8S03mtZ1IgVR1uiBL2N6oohHIAunk8DIAmNWI-zgycTgzUGU7mvPkKH43qO8Ua1-13tCUBKKa8VxcotZ67Mxm1QAvBGoDnTKwWMwghLzs6d6WViXQg6eWlJcpBA"}
43294384
```
43304385
4386+
```coffeescript
4387+
root.signed = this.claims.sign_jwt_rs256(signing_secret: """-----BEGIN RSA PRIVATE KEY-----
4388+
... signature data ...
4389+
-----END RSA PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4390+
4391+
# In: {"claims":{"sub":"user123"}}
4392+
# Out: {"signed":"<signed JWT token>"}
4393+
```
4394+
43314395
=== `sign_jwt_rs384`
43324396
43334397
Hash and sign an object representing JSON Web Token (JWT) claims using RS384.
@@ -4338,6 +4402,7 @@ Introduced in version v4.18.0.
43384402
==== Parameters
43394403
43404404
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4405+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
43414406
43424407
==== Examples
43434408
@@ -4351,6 +4416,15 @@ root.signed = this.claims.sign_jwt_rs384("""-----BEGIN RSA PRIVATE KEY-----
43514416
# Out: {"signed":"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm1vb2QiOiJEaXNkYWluZnVsIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.orcXYBcjVE5DU7mvq4KKWFfNdXR4nEY_xupzWoETRpYmQZIozlZnM_nHxEk2dySvpXlAzVm7kgOPK2RFtGlOVaNRIa3x-pMMr-bhZTno4L8Hl4sYxOks3bWtjK7wql4uqUbqThSJB12psAXw2-S-I_FMngOPGIn4jDT9b802ottJSvTpXcy0-eKTjrV2PSkRRu-EYJh0CJZW55MNhqlt6kCGhAXfbhNazN3ASX-dmpd_JixyBKphrngr_zRA-FCn_Xf3QQDA-5INopb4Yp5QiJ7UxVqQEKI80X_JvJqz9WE1qiAw8pq5-xTen1t7zTP-HT1NbbD3kltcNa3G8acmNg"}
43524417
```
43534418
4419+
```coffeescript
4420+
root.signed = this.claims.sign_jwt_rs384(signing_secret: """-----BEGIN RSA PRIVATE KEY-----
4421+
... signature data ...
4422+
-----END RSA PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4423+
4424+
# In: {"claims":{"sub":"user123"}}
4425+
# Out: {"signed":"<signed JWT token>"}
4426+
```
4427+
43544428
=== `sign_jwt_rs512`
43554429
43564430
Hash and sign an object representing JSON Web Token (JWT) claims using RS512.
@@ -4361,6 +4435,7 @@ Introduced in version v4.18.0.
43614435
==== Parameters
43624436
43634437
*`signing_secret`* &lt;string&gt; The secret to use for signing the token.
4438+
*`headers`* &lt;(optional) unknown&gt; Optional object of JWT header fields to include in the token. Keys "alg", "typ", "jku", "jwk", "x5u", "x5c", "x5t","x5t#S256" and "crit" will be ignored if provided.
43644439
43654440
==== Examples
43664441
@@ -4374,6 +4449,15 @@ root.signed = this.claims.sign_jwt_rs512("""-----BEGIN RSA PRIVATE KEY-----
43744449
# Out: {"signed":"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm1vb2QiOiJEaXNkYWluZnVsIiwic3ViIjoiMTIzNDU2Nzg5MCJ9.rsMp_X5HMrUqKnZJIxo27aAoscovRA6SSQYR9rq7pifIj0YHXxMyNyOBDGnvVALHKTi25VUGHpfNUW0VVMmae0A4t_ObNU6hVZHguWvetKZZq4FZpW1lgWHCMqgPGwT5_uOqwYCH6r8tJuZT3pqXeL0CY4putb1AN2w6CVp620nh3l8d3XWb4jaifycd_4CEVCqHuWDmohfug4VhmoVKlIXZkYoAQowgHlozATDssBSWdYtv107Wd2AzEoiXPu6e3pflsuXULlyqQnS4ELEKPYThFLafh1NqvZDPddqozcPZ-iODBW-xf3A4DYDdivnMYLrh73AZOGHexxu8ay6nDA"}
43754450
```
43764451
4452+
```coffeescript
4453+
root.signed = this.claims.sign_jwt_rs512(signing_secret: """-----BEGIN RSA PRIVATE KEY-----
4454+
... signature data ...
4455+
-----END RSA PRIVATE KEY-----""", headers: {"kid": "my-key", "x": "y"})
4456+
4457+
# In: {"claims":{"sub":"user123"}}
4458+
# Out: {"signed":"<signed JWT token>"}
4459+
```
4460+
43774461
== GeoIP
43784462
43794463
=== `geoip_anonymous_ip`

internal/impl/crypto/jwt_sign.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,31 @@ func jwtSigner(secretDecoder secretDecoderFunc, method jwt.SigningMethod) blobla
4848
return nil, fmt.Errorf("failed to decode signing_secret: %w", err)
4949
}
5050

51+
h, err := args.Get("headers")
52+
if err != nil {
53+
return nil, err
54+
}
55+
var customHeaders map[string]any
56+
if h != nil {
57+
switch htype := h.(type) {
58+
case map[string]any:
59+
customHeaders = make(map[string]any, len(htype))
60+
for key, value := range htype {
61+
if key == "alg" || key == "typ" || key == "jku" || key == "jwk" || key == "x5u" || key == "x5c" || key == "x5t" || key == "x5t#S256" || key == "crit" {
62+
continue
63+
}
64+
customHeaders[key] = value
65+
}
66+
default:
67+
return nil, fmt.Errorf("headers parameter must be an object (map), got %T", h)
68+
}
69+
}
70+
5171
return bloblang.ObjectMethod(func(obj map[string]any) (any, error) {
5272
token := jwt.NewWithClaims(method, jwt.MapClaims(obj))
73+
for key, value := range customHeaders {
74+
token.Header[key] = value
75+
}
5376
signed, err := token.SignedString(s)
5477
if err != nil {
5578
return "", fmt.Errorf("failed to sign token: %w", err)
@@ -74,6 +97,7 @@ func registerSignJwtMethod(m signJwtMethodSpec) error {
7497
Category("JSON Web Tokens").
7598
Description(fmt.Sprintf("Hash and sign an object representing JSON Web Token (JWT) claims using %s.", m.method.Alg())).
7699
Param(bloblang.NewStringParam("signing_secret").Description("The secret to use for signing the token.")).
100+
Param(bloblang.NewAnyParam("headers").Optional().Description("Optional object of JWT header fields to include in the token. Keys \"alg\", \"typ\", \"jku\", \"jwk\", \"x5u\", \"x5c\", \"x5t\",\"x5t#S256\" and \"crit\" will be ignored if provided.")).
77101
Version(m.version)
78102

79103
if m.sampleSignature != "" {
@@ -87,6 +111,15 @@ func registerSignJwtMethod(m signJwtMethodSpec) error {
87111
)
88112
}
89113

114+
spec.ExampleNotTested(
115+
"",
116+
fmt.Sprintf(`root.signed = this.claims.%s(signing_secret: """%s""", headers: {"kid": "my-key", "x": "y"})`, m.name, m.dummySecret),
117+
[2]string{
118+
`{"claims":{"sub":"user123"}}`,
119+
`{"signed":"<signed JWT token>"}`,
120+
},
121+
)
122+
90123
return bloblang.RegisterMethodV2(m.name, spec, jwtSigner(m.secretDecoder, m.method))
91124
}
92125

0 commit comments

Comments
 (0)