@@ -20,6 +20,9 @@ class JWT {
2020 /// value is a timestamp (number of seconds since epoch) in UTC if
2121 /// [issueAtUtc] is true, it is compared to the value of the 'iat' claim.
2222 /// Verification fails if the 'iat' claim is before [issueAt] .
23+ ///
24+ /// If the embedded `payload` is not a JSON map (but rather just a plain string),
25+ /// none of the verifications are executed. In that case only the signature is verified.
2326 static JWT verify (
2427 String token,
2528 JWTKey key, {
@@ -35,6 +38,13 @@ class JWT {
3538 }) {
3639 try {
3740 final parts = token.split ('.' );
41+
42+ if (parts.length != 3 ) {
43+ throw JWTInvalidException (
44+ 'token does not use JWS Compact Serialization' ,
45+ );
46+ }
47+
3848 final header = jsonBase64.decode (base64Padded (parts[0 ]));
3949
4050 if (header == null || header is ! Map <String , dynamic >) {
@@ -54,10 +64,11 @@ class JWT {
5464 throw JWTInvalidException ('invalid signature' );
5565 }
5666
57- dynamic payload;
67+ Object payload;
5868
5969 try {
60- payload = jsonBase64.decode (base64Padded (parts[1 ]));
70+ payload =
71+ jsonBase64.decode (base64Padded (parts[1 ])) as Map <String , dynamic >;
6172 } catch (ex) {
6273 payload = utf8.decode (base64Url.decode (base64Padded (parts[1 ])));
6374 }
@@ -194,18 +205,15 @@ class JWT {
194205 ///
195206 /// This also sets [JWT.audience] , [JWT.subject] , [JWT.issuer] , and
196207 /// [JWT.jwtId] even though they are not verified. Use with caution.
208+ ///
209+ /// This methods only supports map payloads. For `String` payloads use `verify` .
197210 static JWT decode (String token) {
198211 try {
199212 final parts = token.split ('.' );
200- var header = jsonBase64.decode (base64Padded (parts[0 ]));
201-
202- dynamic payload;
213+ final header = jsonBase64.decode (base64Padded (parts[0 ]));
203214
204- try {
205- payload = jsonBase64.decode (base64Padded (parts[1 ]));
206- } catch (ex) {
207- payload = utf8.decode (base64Url.decode (base64Padded (parts[1 ])));
208- }
215+ final payload =
216+ (jsonBase64.decode (base64Padded (parts[1 ])) as Map <String , dynamic >);
209217
210218 final audiance = _parseAud (payload['aud' ]);
211219 final issuer = payload['iss' ]? .toString ();
@@ -240,16 +248,34 @@ class JWT {
240248
241249 /// JSON Web Token
242250 JWT (
243- this . payload, {
251+ Object payload, {
244252 this .audience,
245253 this .subject,
246254 this .issuer,
247255 this .jwtId,
248256 this .header,
249- });
257+ }) : _payload = payload ;
250258
251- /// Custom claims
252- dynamic payload;
259+ late Object _payload;
260+
261+ /// The token's payload, either as a `Map<String, dynamic>` or plain `String`
262+ /// (in case it was not a JSON-encoded map).
263+ ///
264+ /// If it's a map, it has all claims, containing the utilized registered claims
265+ /// as well custom ones added.
266+ Object get payload => _payload;
267+
268+ void set payload (Object value) {
269+ if (value is String ) {
270+ _payload = value;
271+ } else if (value is Map ) {
272+ _payload = Map <String , dynamic >.from (value);
273+ } else {
274+ throw Exception (
275+ 'Unexpected `payload` type `${payload .runtimeType }`, must be either `String` or `Map<String, *>`' ,
276+ );
277+ }
278+ }
253279
254280 /// Audience claim
255281 Audience ? audience;
@@ -281,7 +307,8 @@ class JWT {
281307 bool noIssueAt = false ,
282308 }) {
283309 try {
284- if (payload is Map <String , dynamic > || payload is Map <dynamic , dynamic >) {
310+ var payload = this .payload;
311+ if (payload is Map <String , dynamic >) {
285312 try {
286313 payload = Map <String , dynamic >.from (payload);
287314
0 commit comments