001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose; 019 020 021import com.nimbusds.jose.jwk.JWK; 022import com.nimbusds.jose.util.Base64; 023import com.nimbusds.jose.util.Base64URL; 024import com.nimbusds.jose.util.JSONObjectUtils; 025import com.nimbusds.jose.util.X509CertChainUtils; 026import net.jcip.annotations.Immutable; 027 028import java.net.URI; 029import java.text.ParseException; 030import java.util.*; 031 032 033/** 034 * JSON Web Signature (JWS) header. This class is immutable. 035 * 036 * <p>Supports the following {@link #getRegisteredParameterNames registered 037 * header parameters}: 038 * 039 * <ul> 040 * <li>alg 041 * <li>jku 042 * <li>jwk 043 * <li>x5u 044 * <li>x5t 045 * <li>x5t#S256 046 * <li>x5c 047 * <li>kid 048 * <li>typ 049 * <li>cty 050 * <li>crit 051 * <li>b64 052 * </ul> 053 * 054 * <p>The header may also include {@link #getCustomParams custom 055 * parameters}; these will be serialised and parsed along the registered ones. 056 * 057 * <p>Example header of a JSON Web Signature (JWS) object using the 058 * {@link JWSAlgorithm#HS256 HMAC SHA-256 algorithm}: 059 * 060 * <pre> 061 * { 062 * "alg" : "HS256" 063 * } 064 * </pre> 065 * 066 * @author Vladimir Dzhuvinov 067 * @version 2024-04-20 068 */ 069@Immutable 070public final class JWSHeader extends CommonSEHeader { 071 072 073 private static final long serialVersionUID = 1L; 074 075 076 /** 077 * The registered parameter names. 078 */ 079 private static final Set<String> REGISTERED_PARAMETER_NAMES; 080 081 082 static { 083 Set<String> p = new HashSet<>(); 084 085 p.add(HeaderParameterNames.ALGORITHM); 086 p.add(HeaderParameterNames.JWK_SET_URL); 087 p.add(HeaderParameterNames.JWK); 088 p.add(HeaderParameterNames.X_509_CERT_URL); 089 p.add(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT); 090 p.add(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT); 091 p.add(HeaderParameterNames.X_509_CERT_CHAIN); 092 p.add(HeaderParameterNames.KEY_ID); 093 p.add(HeaderParameterNames.TYPE); 094 p.add(HeaderParameterNames.CONTENT_TYPE); 095 p.add(HeaderParameterNames.CRITICAL); 096 p.add(HeaderParameterNames.BASE64_URL_ENCODE_PAYLOAD); 097 098 REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p); 099 } 100 101 102 /** 103 * Builder for constructing JSON Web Signature (JWS) headers. 104 * 105 * <p>Example usage: 106 * 107 * <pre> 108 * JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256) 109 * .contentType("text/plain") 110 * .customParam("exp", new Date().getTime()) 111 * .build(); 112 * </pre> 113 */ 114 public static class Builder { 115 116 117 /** 118 * The JWS algorithm. 119 */ 120 private final JWSAlgorithm alg; 121 122 123 /** 124 * The JOSE object type. 125 */ 126 private JOSEObjectType typ; 127 128 129 /** 130 * The content type. 131 */ 132 private String cty; 133 134 135 /** 136 * The critical headers. 137 */ 138 private Set<String> crit; 139 140 141 /** 142 * Public JWK Set URL. 143 */ 144 private URI jku; 145 146 147 /** 148 * Public JWK. 149 */ 150 private JWK jwk; 151 152 153 /** 154 * X.509 certificate URL. 155 */ 156 private URI x5u; 157 158 159 /** 160 * X.509 certificate SHA-1 thumbprint. 161 */ 162 @Deprecated 163 private Base64URL x5t; 164 165 166 /** 167 * X.509 certificate SHA-256 thumbprint. 168 */ 169 private Base64URL x5t256; 170 171 172 /** 173 * The X.509 certificate chain corresponding to the key used to 174 * sign the JWS object. 175 */ 176 private List<Base64> x5c; 177 178 179 /** 180 * Key ID. 181 */ 182 private String kid; 183 184 185 /** 186 * Base64URL encoding of the payload, the default is 187 * {@code true} for standard JWS serialisation. 188 */ 189 private boolean b64 = true; 190 191 192 /** 193 * Custom header parameters. 194 */ 195 private Map<String,Object> customParams; 196 197 198 /** 199 * The parsed Base64URL. 200 */ 201 private Base64URL parsedBase64URL; 202 203 204 /** 205 * Creates a new JWS header builder. 206 * 207 * @param alg The JWS algorithm ({@code alg}) parameter. Must 208 * not be "none" or {@code null}. 209 */ 210 public Builder(final JWSAlgorithm alg) { 211 212 if (alg.getName().equals(Algorithm.NONE.getName())) { 213 throw new IllegalArgumentException("The JWS algorithm \"alg\" cannot be \"none\""); 214 } 215 216 this.alg = alg; 217 } 218 219 220 /** 221 * Creates a new JWS header builder with the parameters from 222 * the specified header. 223 * 224 * @param jwsHeader The JWS header to use. Must not be 225 * {@code null}. 226 */ 227 public Builder(final JWSHeader jwsHeader) { 228 229 this(jwsHeader.getAlgorithm()); 230 231 typ = jwsHeader.getType(); 232 cty = jwsHeader.getContentType(); 233 crit = jwsHeader.getCriticalParams(); 234 235 jku = jwsHeader.getJWKURL(); 236 jwk = jwsHeader.getJWK(); 237 x5u = jwsHeader.getX509CertURL(); 238 x5t = jwsHeader.getX509CertThumbprint(); 239 x5t256 = jwsHeader.getX509CertSHA256Thumbprint(); 240 x5c = jwsHeader.getX509CertChain(); 241 kid = jwsHeader.getKeyID(); 242 b64 = jwsHeader.isBase64URLEncodePayload(); 243 customParams = jwsHeader.getCustomParams(); 244 } 245 246 247 /** 248 * Sets the type ({@code typ}) parameter. 249 * 250 * @param typ The type parameter, {@code null} if not 251 * specified. 252 * 253 * @return This builder. 254 */ 255 public Builder type(final JOSEObjectType typ) { 256 257 this.typ = typ; 258 return this; 259 } 260 261 262 /** 263 * Sets the content type ({@code cty}) parameter. 264 * 265 * @param cty The content type parameter, {@code null} if not 266 * specified. 267 * 268 * @return This builder. 269 */ 270 public Builder contentType(final String cty) { 271 272 this.cty = cty; 273 return this; 274 } 275 276 277 /** 278 * Sets the critical header parameters ({@code crit}) 279 * parameter. 280 * 281 * @param crit The names of the critical header parameters, 282 * empty set or {@code null} if none. 283 * 284 * @return This builder. 285 */ 286 public Builder criticalParams(final Set<String> crit) { 287 288 this.crit = crit; 289 return this; 290 } 291 292 293 /** 294 * Sets the public JSON Web Key (JWK) Set URL ({@code jku}) 295 * parameter. 296 * 297 * @param jku The public JSON Web Key (JWK) Set URL parameter, 298 * {@code null} if not specified. 299 * 300 * @return This builder. 301 */ 302 public Builder jwkURL(final URI jku) { 303 304 this.jku = jku; 305 return this; 306 } 307 308 309 /** 310 * Sets the public JSON Web Key (JWK) ({@code jwk}) parameter. 311 * 312 * @param jwk The public JSON Web Key (JWK) ({@code jwk}) 313 * parameter, {@code null} if not specified. 314 * 315 * @return This builder. 316 */ 317 public Builder jwk(final JWK jwk) { 318 319 if (jwk != null && jwk.isPrivate()) { 320 throw new IllegalArgumentException("The JWK must be public"); 321 } 322 323 this.jwk = jwk; 324 return this; 325 } 326 327 328 /** 329 * Sets the X.509 certificate URL ({@code x5u}) parameter. 330 * 331 * @param x5u The X.509 certificate URL parameter, {@code null} 332 * if not specified. 333 * 334 * @return This builder. 335 */ 336 public Builder x509CertURL(final URI x5u) { 337 338 this.x5u = x5u; 339 return this; 340 } 341 342 343 /** 344 * Sets the X.509 certificate SHA-1 thumbprint ({@code x5t}) 345 * parameter. 346 * 347 * @param x5t The X.509 certificate SHA-1 thumbprint parameter, 348 * {@code null} if not specified. 349 * 350 * @return This builder. 351 */ 352 @Deprecated 353 public Builder x509CertThumbprint(final Base64URL x5t) { 354 355 this.x5t = x5t; 356 return this; 357 } 358 359 360 /** 361 * Sets the X.509 certificate SHA-256 thumbprint 362 * ({@code x5t#S256}) parameter. 363 * 364 * @param x5t256 The X.509 certificate SHA-256 thumbprint 365 * parameter, {@code null} if not specified. 366 * 367 * @return This builder. 368 */ 369 public Builder x509CertSHA256Thumbprint(final Base64URL x5t256) { 370 371 this.x5t256 = x5t256; 372 return this; 373 } 374 375 376 /** 377 * Sets the X.509 certificate chain parameter ({@code x5c}) 378 * corresponding to the key used to sign the JWS object. 379 * 380 * @param x5c The X.509 certificate chain parameter, 381 * {@code null} if not specified. 382 * 383 * @return This builder. 384 */ 385 public Builder x509CertChain(final List<Base64> x5c) { 386 387 this.x5c = x5c; 388 return this; 389 } 390 391 392 /** 393 * Sets the key ID ({@code kid}) parameter. 394 * 395 * @param kid The key ID parameter, {@code null} if not 396 * specified. 397 * 398 * @return This builder. 399 */ 400 public Builder keyID(final String kid) { 401 402 this.kid = kid; 403 return this; 404 } 405 406 407 /** 408 * Sets the Base64URL encode payload ({@code b64}) parameter. 409 * 410 * @param b64 {@code true} to Base64URL encode the payload 411 * for standard JWS serialisation, {@code false} for 412 * unencoded payload (RFC 7797). 413 * 414 * @return This builder. 415 */ 416 public Builder base64URLEncodePayload(final boolean b64) { 417 418 this.b64 = b64; 419 return this; 420 } 421 422 423 /** 424 * Sets a custom (non-registered) parameter. 425 * 426 * @param name The name of the custom parameter. Must not 427 * match a registered parameter name and must not 428 * be {@code null}. 429 * @param value The value of the custom parameter, should map 430 * to a valid JSON entity, {@code null} if not 431 * specified. 432 * 433 * @return This builder. 434 * 435 * @throws IllegalArgumentException If the specified parameter 436 * name matches a registered 437 * parameter name. 438 */ 439 public Builder customParam(final String name, final Object value) { 440 441 if (getRegisteredParameterNames().contains(name)) { 442 throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a registered name"); 443 } 444 445 if (customParams == null) { 446 customParams = new HashMap<>(); 447 } 448 449 customParams.put(name, value); 450 451 return this; 452 } 453 454 455 /** 456 * Sets the custom (non-registered) parameters. The values must 457 * be serialisable to a JSON entity, otherwise will be ignored. 458 * 459 * @param customParameters The custom parameters, empty map or 460 * {@code null} if none. 461 * 462 * @return This builder. 463 */ 464 public Builder customParams(final Map<String, Object> customParameters) { 465 466 this.customParams = customParameters; 467 return this; 468 } 469 470 471 /** 472 * Sets the parsed Base64URL. 473 * 474 * @param base64URL The parsed Base64URL, {@code null} if the 475 * header is created from scratch. 476 * 477 * @return This builder. 478 */ 479 public Builder parsedBase64URL(final Base64URL base64URL) { 480 481 this.parsedBase64URL = base64URL; 482 return this; 483 } 484 485 486 /** 487 * Builds a new JWS header. 488 * 489 * @return The JWS header. 490 */ 491 public JWSHeader build() { 492 493 return new JWSHeader( 494 alg, typ, cty, crit, 495 jku, jwk, x5u, x5t, x5t256, x5c, kid, b64, 496 customParams, parsedBase64URL); 497 } 498 } 499 500 501 /** 502 * Base64URL encoding of the payload, {@code true} for standard JWS 503 * serialisation, {@code false} for unencoded payload (RFC 7797). 504 */ 505 private final boolean b64; 506 507 508 /** 509 * Creates a new minimal JSON Web Signature (JWS) header. 510 * 511 * <p>Note: Use {@link PlainHeader} to create a header with algorithm 512 * {@link Algorithm#NONE none}. 513 * 514 * @param alg The JWS algorithm ({@code alg}) parameter. Must not be 515 * "none" or {@code null}. 516 */ 517 public JWSHeader(final JWSAlgorithm alg) { 518 519 this(alg, null, null, null, null, null, null, null, null, null, null, true,null, null); 520 } 521 522 523 /** 524 * Creates a new JSON Web Signature (JWS) header. 525 * 526 * <p>Note: Use {@link PlainHeader} to create a header with algorithm 527 * {@link Algorithm#NONE none}. 528 * 529 * @param alg The JWS algorithm ({@code alg}) parameter. 530 * Must not be "none" or {@code null}. 531 * @param typ The type ({@code typ}) parameter, 532 * {@code null} if not specified. 533 * @param cty The content type ({@code cty}) parameter, 534 * {@code null} if not specified. 535 * @param crit The names of the critical header 536 * ({@code crit}) parameters, empty set or 537 * {@code null} if none. 538 * @param jku The JSON Web Key (JWK) Set URL ({@code jku}) 539 * parameter, {@code null} if not specified. 540 * @param jwk The X.509 certificate URL ({@code jwk}) 541 * parameter, {@code null} if not specified. 542 * @param x5u The X.509 certificate URL parameter 543 * ({@code x5u}), {@code null} if not specified. 544 * @param x5t The X.509 certificate SHA-1 thumbprint 545 * ({@code x5t}) parameter, {@code null} if not 546 * specified. 547 * @param x5t256 The X.509 certificate SHA-256 thumbprint 548 * ({@code x5t#S256}) parameter, {@code null} if 549 * not specified. 550 * @param x5c The X.509 certificate chain ({@code x5c}) 551 * parameter, {@code null} if not specified. 552 * @param kid The key ID ({@code kid}) parameter, 553 * {@code null} if not specified. 554 * @param customParams The custom parameters, empty map or 555 * {@code null} if none. 556 * @param parsedBase64URL The parsed Base64URL, {@code null} if the 557 * header is created from scratch. 558 */ 559 @Deprecated 560 public JWSHeader(final JWSAlgorithm alg, 561 final JOSEObjectType typ, 562 final String cty, 563 final Set<String> crit, 564 final URI jku, 565 final JWK jwk, 566 final URI x5u, 567 final Base64URL x5t, 568 final Base64URL x5t256, 569 final List<Base64> x5c, 570 final String kid, 571 final Map<String,Object> customParams, 572 final Base64URL parsedBase64URL) { 573 574 this(alg, typ, cty, crit, jku, jwk, x5u, x5t, x5t256, x5c, kid, true, customParams, parsedBase64URL); 575 } 576 577 578 /** 579 * Creates a new JSON Web Signature (JWS) header. 580 * 581 * <p>Note: Use {@link PlainHeader} to create a header with algorithm 582 * {@link Algorithm#NONE none}. 583 * 584 * @param alg The JWS algorithm ({@code alg}) parameter. 585 * Must not be "none" or {@code null}. 586 * @param typ The type ({@code typ}) parameter, 587 * {@code null} if not specified. 588 * @param cty The content type ({@code cty}) parameter, 589 * {@code null} if not specified. 590 * @param crit The names of the critical header 591 * ({@code crit}) parameters, empty set or 592 * {@code null} if none. 593 * @param jku The JSON Web Key (JWK) Set URL ({@code jku}) 594 * parameter, {@code null} if not specified. 595 * @param jwk The X.509 certificate URL ({@code jwk}) 596 * parameter, {@code null} if not specified. 597 * @param x5u The X.509 certificate URL parameter 598 * ({@code x5u}), {@code null} if not specified. 599 * @param x5t The X.509 certificate SHA-1 thumbprint 600 * ({@code x5t}) parameter, {@code null} if not 601 * specified. 602 * @param x5t256 The X.509 certificate SHA-256 thumbprint 603 * ({@code x5t#S256}) parameter, {@code null} if 604 * not specified. 605 * @param x5c The X.509 certificate chain ({@code x5c}) 606 * parameter, {@code null} if not specified. 607 * @param kid The key ID ({@code kid}) parameter, 608 * {@code null} if not specified. 609 * @param b64 {@code true} to Base64URL encode the payload 610 * for standard JWS serialisation, {@code false} 611 * for unencoded payload (RFC 7797). 612 * @param customParams The custom parameters, empty map or 613 * {@code null} if none. 614 * @param parsedBase64URL The parsed Base64URL, {@code null} if the 615 * header is created from scratch. 616 */ 617 public JWSHeader(final JWSAlgorithm alg, 618 final JOSEObjectType typ, 619 final String cty, 620 final Set<String> crit, 621 final URI jku, 622 final JWK jwk, 623 final URI x5u, 624 final Base64URL x5t, 625 final Base64URL x5t256, 626 final List<Base64> x5c, 627 final String kid, 628 final boolean b64, 629 final Map<String,Object> customParams, 630 final Base64URL parsedBase64URL) { 631 632 super(alg, typ, cty, crit, jku, jwk, x5u, x5t, x5t256, x5c, kid, customParams, parsedBase64URL); 633 634 if (alg.getName().equals(Algorithm.NONE.getName())) { 635 throw new IllegalArgumentException("The JWS algorithm \"alg\" cannot be \"none\""); 636 } 637 638 this.b64 = b64; 639 } 640 641 642 /** 643 * Deep copy constructor. 644 * 645 * @param jwsHeader The JWS header to copy. Must not be {@code null}. 646 */ 647 public JWSHeader(final JWSHeader jwsHeader) { 648 649 this( 650 jwsHeader.getAlgorithm(), 651 jwsHeader.getType(), 652 jwsHeader.getContentType(), 653 jwsHeader.getCriticalParams(), 654 jwsHeader.getJWKURL(), 655 jwsHeader.getJWK(), 656 jwsHeader.getX509CertURL(), 657 jwsHeader.getX509CertThumbprint(), 658 jwsHeader.getX509CertSHA256Thumbprint(), 659 jwsHeader.getX509CertChain(), 660 jwsHeader.getKeyID(), 661 jwsHeader.isBase64URLEncodePayload(), 662 jwsHeader.getCustomParams(), 663 jwsHeader.getParsedBase64URL() 664 ); 665 } 666 667 668 /** 669 * Gets the registered parameter names for JWS headers. 670 * 671 * @return The registered parameter names, as an unmodifiable set. 672 */ 673 public static Set<String> getRegisteredParameterNames() { 674 675 return REGISTERED_PARAMETER_NAMES; 676 } 677 678 679 /** 680 * Gets the algorithm ({@code alg}) parameter. 681 * 682 * @return The algorithm parameter. 683 */ 684 @Override 685 public JWSAlgorithm getAlgorithm() { 686 687 return (JWSAlgorithm)super.getAlgorithm(); 688 } 689 690 691 /** 692 * Returns the Base64URL-encode payload ({@code b64}) parameter. 693 * 694 * @return {@code true} to Base64URL encode the payload for standard 695 * JWS serialisation, {@code false} for unencoded payload (RFC 696 * 7797). 697 */ 698 public boolean isBase64URLEncodePayload() { 699 700 return b64; 701 } 702 703 704 @Override 705 public Set<String> getIncludedParams() { 706 Set<String> includedParams = super.getIncludedParams(); 707 if (! isBase64URLEncodePayload()) { 708 includedParams.add(HeaderParameterNames.BASE64_URL_ENCODE_PAYLOAD); 709 } 710 return includedParams; 711 } 712 713 714 @Override 715 public Map<String, Object> toJSONObject() { 716 Map<String, Object> o = super.toJSONObject(); 717 if (! isBase64URLEncodePayload()) { 718 o.put(HeaderParameterNames.BASE64_URL_ENCODE_PAYLOAD, false); 719 } 720 return o; 721 } 722 723 724 /** 725 * Parses a JWS header from the specified JSON object. 726 * 727 * @param jsonObject The JSON object to parse. Must not be 728 * {@code null}. 729 * 730 * @return The JWS header. 731 * 732 * @throws ParseException If the specified JSON object doesn't 733 * represent a valid JWS header. 734 */ 735 public static JWSHeader parse(final Map<String, Object> jsonObject) 736 throws ParseException { 737 738 return parse(jsonObject, null); 739 } 740 741 742 /** 743 * Parses a JWS header from the specified JSON object. 744 * 745 * @param jsonObject The JSON object to parse. Must not be 746 * {@code null}. 747 * @param parsedBase64URL The original parsed Base64URL, {@code null} 748 * if not applicable. 749 * 750 * @return The JWS header. 751 * 752 * @throws ParseException If the specified JSON object doesn't 753 * represent a valid JWS header. 754 */ 755 public static JWSHeader parse(final Map<String, Object> jsonObject, 756 final Base64URL parsedBase64URL) 757 throws ParseException { 758 759 // Get the "alg" parameter 760 Algorithm alg = Header.parseAlgorithm(jsonObject); 761 762 if (! (alg instanceof JWSAlgorithm)) { 763 throw new ParseException("Not a JWS header", 0); 764 } 765 766 JWSHeader.Builder header = new Builder((JWSAlgorithm)alg).parsedBase64URL(parsedBase64URL); 767 768 // Parse optional + custom parameters 769 for (final String name: jsonObject.keySet()) { 770 771 if(HeaderParameterNames.ALGORITHM.equals(name)) { 772 // skip 773 } else if(HeaderParameterNames.TYPE.equals(name)) { 774 String typValue = JSONObjectUtils.getString(jsonObject, name); 775 if (typValue != null) { 776 header = header.type(new JOSEObjectType(typValue)); 777 } 778 } else if(HeaderParameterNames.CONTENT_TYPE.equals(name)) { 779 header = header.contentType(JSONObjectUtils.getString(jsonObject, name)); 780 } else if(HeaderParameterNames.CRITICAL.equals(name)) { 781 List<String> critValues = JSONObjectUtils.getStringList(jsonObject, name); 782 if (critValues != null) { 783 header = header.criticalParams(new HashSet<>(critValues)); 784 } 785 } else if(HeaderParameterNames.JWK_SET_URL.equals(name)) { 786 header = header.jwkURL(JSONObjectUtils.getURI(jsonObject, name)); 787 } else if(HeaderParameterNames.JWK.equals(name)) { 788 header = header.jwk(CommonSEHeader.parsePublicJWK(JSONObjectUtils.getJSONObject(jsonObject, name))); 789 } else if(HeaderParameterNames.X_509_CERT_URL.equals(name)) { 790 header = header.x509CertURL(JSONObjectUtils.getURI(jsonObject, name)); 791 } else if(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT.equals(name)) { 792 header = header.x509CertThumbprint(Base64URL.from(JSONObjectUtils.getString(jsonObject, name))); 793 } else if(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT.equals(name)) { 794 header = header.x509CertSHA256Thumbprint(Base64URL.from(JSONObjectUtils.getString(jsonObject, name))); 795 } else if(HeaderParameterNames.X_509_CERT_CHAIN.equals(name)) { 796 header = header.x509CertChain(X509CertChainUtils.toBase64List(JSONObjectUtils.getJSONArray(jsonObject, name))); 797 } else if(HeaderParameterNames.KEY_ID.equals(name)) { 798 header = header.keyID(JSONObjectUtils.getString(jsonObject, name)); 799 } else if(HeaderParameterNames.BASE64_URL_ENCODE_PAYLOAD.equals(name)) { 800 header = header.base64URLEncodePayload(JSONObjectUtils.getBoolean(jsonObject, name)); 801 } else { 802 header = header.customParam(name, jsonObject.get(name)); 803 } 804 } 805 806 return header.build(); 807 } 808 809 810 /** 811 * Parses a JWS header from the specified JSON object string. 812 * 813 * @param jsonString The JSON string to parse. Must not be 814 * {@code null}. 815 * 816 * @return The JWS header. 817 * 818 * @throws ParseException If the specified JSON object string doesn't 819 * represent a valid JWS header. 820 */ 821 public static JWSHeader parse(final String jsonString) 822 throws ParseException { 823 824 return parse(jsonString, null); 825 } 826 827 828 /** 829 * Parses a JWS header from the specified JSON object string. 830 * 831 * @param jsonString The JSON string to parse. Must not be 832 * {@code null}. 833 * @param parsedBase64URL The original parsed Base64URL, {@code null} 834 * if not applicable. 835 * 836 * @return The JWS header. 837 * 838 * @throws ParseException If the specified JSON object string doesn't 839 * represent a valid JWS header. 840 */ 841 public static JWSHeader parse(final String jsonString, 842 final Base64URL parsedBase64URL) 843 throws ParseException { 844 845 return parse(JSONObjectUtils.parse(jsonString, MAX_HEADER_STRING_LENGTH), parsedBase64URL); 846 } 847 848 849 /** 850 * Parses a JWS header from the specified Base64URL. 851 * 852 * @param base64URL The Base64URL to parse. Must not be {@code null}. 853 * 854 * @return The JWS header. 855 * 856 * @throws ParseException If the specified Base64URL doesn't represent 857 * a valid JWS header. 858 */ 859 public static JWSHeader parse(final Base64URL base64URL) 860 throws ParseException { 861 862 return parse(base64URL.decodeToString(), base64URL); 863 } 864}