32

I am writing a Flutter/Dart application and am getting a JWT back from an auth server that has some claims I need to use. I have looked at various (4 so far) Dart JWT libraries -- but all are either too old and no longer work with Dart 2, etc. or they need the secret to decode the JWT which makes no sense and isn't correct (or possible since I have no access ).

So -- how can one get a JWT and get the claims from it within a "modern" Dart/Flutter application?

sjmcdowall
  • 1,471
  • 4
  • 15
  • 27

5 Answers5

75

JWT tokens are just base64 encoded JSON strings (3 of them, separated by dots):

import 'dart:convert';

Map<String, dynamic> parseJwt(String token) {
  final parts = token.split('.');
  if (parts.length != 3) {
    throw Exception('invalid token');
  }

  final payload = _decodeBase64(parts[1]);
  final payloadMap = json.decode(payload);
  if (payloadMap is! Map<String, dynamic>) {
    throw Exception('invalid payload');
  }

  return payloadMap;
}

String _decodeBase64(String str) {
  String output = str.replaceAll('-', '+').replaceAll('_', '/');

  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw Exception('Illegal base64url string!"');
  }

  return utf8.decode(base64Url.decode(output));
}
boformer
  • 28,207
  • 10
  • 81
  • 66
  • 2
    This is PERFECT. It was the padding that was confusing me -- this is a very nice routine -- thank you! Now, why this little routine isn't in a nice JWT package I have no idea! :) (Or if it is it's not easy to see!) – sjmcdowall Aug 26 '18 at 13:08
  • I think I just took it from one of the Dart 1 JWT packages, added a few types, lowercase constants... – boformer Aug 26 '18 at 14:09
  • Thank you It worked for me. I print utf8.decode(base64url.decode(output)).. the result is String. How do I get only one key-value? – BIS Tech Feb 28 '19 at 06:38
  • when you run `parseJwt()`, you get a `Map` result. Use `map['key']` to get the value for a key. – boformer Feb 28 '19 at 16:26
  • I have one question about JWT using with flutter application, if we have a large users ( 1 to 2 lakhs users ) in our mobile application is there any problem or which is the maximum number of users, that are allowed in JWT implementation. – Ragesh P Raju Oct 07 '19 at 05:54
13

Use 'base64Url.normalize()' function. That's what _decodeBase64() does from the answer above!

String getJsonFromJWT(String splittedToken){
  String normalizedSource = base64Url.normalize(encodedStr);
  return utf8.decode(base64Url.decode(normalizedSource));
}
TGLEE
  • 131
  • 1
  • 6
5

As of this writing, the jaguar_jwt package is being actively maintained. Although it is not clearly documented, it does have a public method that will decode Base64Url encoding. It does basically the same thing as the accepted answer.

//import 'package:jaguar_jwt/jaguar_jwt.dart';

final String token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ4MjAxNjIsImlhdCI6MTU1NDc3Njk2MiwiaXNzIjoiU3VyYWdjaCIsInN1YiI6IjQifQ.bg5B_k9WCmxiu2epuZo_Tpt_KZC4N9ve_2GEdrulcXM';
final parts = token.split('.');
final payload = parts[1];
final String decoded = B64urlEncRfc7515.decodeUtf8(payload);

This gives a JSON string, which for this particular example is:

{
  "exp":1554820162,
  "iat":1554776962,
  "iss":"Suragch",
  "sub":"4"
}

See also:

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
3

you can use jwt_decoder package to decode and/or check if you token is expired

 //to get claims from your token
 main () {
   String yourToken = "Your JWT";
   Map<String, dynamic> decodedToken = 
   JwtDecoder.decode(yourToken);

   /*
   If the token has a valid format, you will get a 
   Map<String,dynamic> Your decoded token can look like:
   {
     "sub": "1234567890",
     "name": "Gustavo",
     "iat": 1516239022,
     "exp": 1516239022,
     "randomKey": "something else"
    }
    */
 }

//check if your token is expired
main () {
 String yourToken = "Your JWT";
 bool hasExpired = JwtDecoder.isExpired(yourToken);

 // You will get a true / false response
 // true: if the token is already expired
 // false: if the token is not expired
}

you can get your token expiration date using

main () {
 String yourToken = "Your JWT";
 DateTime expirationDate = JwtDecoder.getExpirationDate(token);

 // 2025-01-13 13:04:18.000
 print(expirationDate);
}

you can also find out how old your token is

// Token payload must include an 'iat' field
main () {
 String yourToken = "Your JWT";
 Duration tokenTime = JwtDecoder.getTokenTime(token);

 // 15
 print(tokenTime.inDays);
}

to learn more about what JWT Decoder can do, visit their package documentation page

Ivan of uganda
  • 382
  • 5
  • 15
2

you can decode JWT base64 by seperate first part of it that contains "."

      String decodeUserData(String code) {
      String normalizedSource = base64Url.normalize(code.split(".")[1]);
      return utf8.decode(base64Url.decode(normalizedSource));
      }