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