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