Skip to content

Commit b051018

Browse files
committed
documentation
1 parent 871c1fc commit b051018

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

docs/usage.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,69 @@ val parser = Jwt.parser()
230230

231231
---
232232

233+
## Using cryptography-kotlin Keys Directly (Parser)
234+
235+
The `co.touchlab.kjwt.ext` package also provides `verifyWith` and `decryptWith` overloads on
236+
`JwtParserBuilder` that accept a raw `String` key plus the corresponding cryptography-kotlin format
237+
type. These are the parser-side twins of the builder extensions described above.
238+
239+
### HMAC (HS256 / HS384 / HS512)
240+
241+
```kotlin
242+
import dev.whyoleg.cryptography.algorithms.HMAC
243+
244+
val parser = Jwt.parser()
245+
.verifyWith(SigningAlgorithm.HS256, hmacKeyString, HMAC.Key.Format.RAW)
246+
.build()
247+
```
248+
249+
### RSA PKCS#1 v1.5 (RS256 / RS384 / RS512)
250+
251+
```kotlin
252+
import dev.whyoleg.cryptography.algorithms.RSA
253+
254+
val parser = Jwt.parser()
255+
.verifyWith(SigningAlgorithm.RS256, pemString, RSA.PublicKey.Format.PEM)
256+
.build()
257+
```
258+
259+
### RSA PSS (PS256 / PS384 / PS512)
260+
261+
```kotlin
262+
val parser = Jwt.parser()
263+
.verifyWith(SigningAlgorithm.PS256, pemString, RSA.PublicKey.Format.PEM)
264+
.build()
265+
```
266+
267+
### ECDSA (ES256 / ES384 / ES512)
268+
269+
```kotlin
270+
import dev.whyoleg.cryptography.algorithms.EC
271+
272+
val parser = Jwt.parser()
273+
.verifyWith(SigningAlgorithm.ES256, rawKeyString, EC.PublicKey.Format.RAW)
274+
.build()
275+
```
276+
277+
All overloads accept an optional `keyId` parameter so the key participates in the standard `kid`
278+
matching strategy described under [Multiple Keys](#multiple-keys-key-rotation).
279+
280+
### Direct key (`dir`) decryption from `ByteArray` or `String`
281+
282+
```kotlin
283+
// from raw bytes
284+
val parser = Jwt.parser()
285+
.decryptWith(cekBytes, EncryptionAlgorithm.Dir)
286+
.build()
287+
288+
// from a UTF-8 string (converted to bytes automatically)
289+
val parser = Jwt.parser()
290+
.decryptWith(cekString, EncryptionAlgorithm.Dir)
291+
.build()
292+
```
293+
294+
---
295+
233296
## Standard Claims
234297

235298
All seven RFC 7519 registered claims are supported via the builder:
@@ -273,11 +336,44 @@ val jws: JwtInstance.Jws = Jwt.builder()
273336
val token: String = jws.compact()
274337
```
275338

339+
### Merging a serializable object into the payload
340+
341+
Use `payload(value)` to merge all fields from a `@Serializable` object into the token payload at once,
342+
instead of setting each claim individually:
343+
344+
```kotlin
345+
@Serializable
346+
data class UserClaims(
347+
@SerialName("role") val role: String? = null,
348+
@SerialName("level") val level: Int? = null,
349+
)
350+
351+
val jws: JwtInstance.Jws = Jwt.builder()
352+
.subject("user-123")
353+
.payload(UserClaims(role = "admin", level = 5)) // merges all fields
354+
.signWith(signingKey)
355+
```
356+
357+
Each field in the object is written as a claim, overwriting any existing value with the same name.
358+
Standard claims set before or after the call (e.g. `.subject()`) are not affected unless the
359+
serializable type defines a field that maps to the same claim name.
360+
276361
## Header Parameters
277362

363+
Header fields can be set either with flat setter methods or with the `header { }` DSL block:
364+
278365
```kotlin
279366
val rsaSigningKey = SigningAlgorithm.RS256.parsePrivateKey(pemBytes, keyId = "key-2024-01")
280367

368+
// Flat setters (new)
369+
val jws: JwtInstance.Jws = Jwt.builder()
370+
.subject("user-123")
371+
.type("JWT") // typ
372+
.contentType("application/json") // cty
373+
.header("x-custom", "value") // extra parameter (reified)
374+
.signWith(rsaSigningKey)
375+
376+
// DSL block (original)
281377
val jws: JwtInstance.Jws = Jwt.builder()
282378
.subject("user-123")
283379
.header {
@@ -289,6 +385,25 @@ val jws: JwtInstance.Jws = Jwt.builder()
289385
val token: String = jws.compact()
290386
```
291387

388+
### Merging a serializable object into the header
389+
390+
Use `header(value)` to merge all fields from a `@Serializable` object into the JOSE header at once:
391+
392+
```kotlin
393+
@Serializable
394+
data class MyHeader(
395+
@SerialName("x-tenant") val tenant: String? = null,
396+
@SerialName("x-version") val version: Int? = null,
397+
)
398+
399+
val jws: JwtInstance.Jws = Jwt.builder()
400+
.subject("user-123")
401+
.header(MyHeader(tenant = "acme", version = 2)) // merges all fields
402+
.signWith(signingKey)
403+
```
404+
405+
Each field in the object is written as a header parameter, overwriting any existing value with the same name.
406+
292407
## Key ID (`kid`)
293408

294409
The `kid` header parameter identifies which key was used to sign or encrypt a token — defined in RFC 7515 §4.1.4 for JWS
@@ -603,6 +718,27 @@ println(payload.subject)
603718

604719
`getPayload<T>()` is available on both `JwtInstance.Jws` and `JwtInstance.Jwe`.
605720

721+
## Custom Header Types
722+
723+
The same pattern works for the JOSE header. Define a `@Serializable` data class whose fields map
724+
to the header parameter names you care about, then call `getHeader<T>()`:
725+
726+
```kotlin
727+
@Serializable
728+
data class MyHeader(
729+
@SerialName("alg") val algorithm: String? = null,
730+
@SerialName("kid") val keyId: String? = null,
731+
@SerialName("x-tenant") val tenant: String? = null,
732+
)
733+
734+
val jws: JwtInstance.Jws = parser.parseSigned(token)
735+
val header: MyHeader = jws.getHeader<MyHeader>()
736+
println(header.keyId)
737+
println(header.tenant)
738+
```
739+
740+
`getHeader<T>()` is available on both `JwtInstance.Jws` and `JwtInstance.Jwe`.
741+
606742
## JWE with Direct Key (`dir`)
607743

608744
For symmetric encryption where the key is used directly as the CEK (no key wrapping):

0 commit comments

Comments
 (0)