I receive jwt token from the api but i don't know how to extract the expire time from the token in Dart.
The token which is received
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InN1amVldGg5MTE3MUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1ZThhZGFlNDIxMDg3MzM1ODBmNDA4NTgiLCJpYXQiOjE1ODYxNTgzMzYsImV4cCI6MTU4Njc2MzEzNn0.EwLTdRXaibNmcbuqVxzEDSfrW37z3eWYIxAifAUsT5I
An elegant solution would be using the jwt_decoder package.
https://pub.dev/packages/jwt_decoder
flutter pub add jwt_decoder
Import it:
import 'package:jwt_decoder/jwt_decoder.dart';
Get all JWT properties:
String yourToken = "Your JWT";
Map<String, dynamic> decodedToken = JwtDecoder.decode(yourToken);
or check only the expiration if that's the case:
String yourToken = "Your JWT";
bool hasExpired = JwtDecoder.isExpired(yourToken);
You can easily use the jwt_decode package.
install jwt_decode
flutter pub add jwt_decode
check isExpired
bool hasExpired = Jwt.isExpired(token);
following is package URL https://pub.dev/packages/jwt_decode
You can do it by decoding it, Speaking in general, JWT token conssist two part (objects), in the above JWT the result of decoding it is :
{
alg: "HS256",
typ: "JWT"
}.
{
email: "sujeeth91171#gmail.com",
userId: "5e8adae42108733580f40858",
iat: 1586158336,
exp: 1586763136
}.
So the expire date is a timestamp (1586763136) which stand for Monday, April 13, 2020 7:32:16 AM.
How ?
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));
}
Dart code credits goes to :boformer
You should use dart:convert. With utf8 you will decode base64 and with json get Map object to call ["exp"] property
import 'dart:convert';
String decodeBase64(String toDecode) {
String res;
try {
while (toDecode.length * 6 % 8 != 0) {
toDecode += "=";
}
res = utf8.decode(base64.decode(toDecode));
} catch (error) {
throw Exception("decodeBase64([toDecode=$toDecode]) \n\t\terror: $error");
}
return res;
}
void main () {
final token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InN1amVldGg5MTE3MUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1ZThhZGFlNDIxMDg3MzM1ODBmNDA4NTgiLCJpYXQiOjE1ODYxNTgzMzYsImV4cCI6MTU4Njc2MzEzNn0.EwLTdRXaibNmcbuqVxzEDSfrW37z3eWYIxAifAUsT5I';
final decoded = json.decode(decodeBase64(token.split(".")[1]));
int exp = decoded["exp"];
print(exp); // 1586763136
}
An alternative solution if you want to use a package:
Install corsac_jwt: https://pub.dev/packages/corsac_jwt#-installing-tab-
import 'package:corsac_jwt/corsac_jwt.dart';
import 'package:corsac_jwt/corsac_jwt.dart';
void main() {
final parsed = JWT.parse('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InN1amVldGg5MTE3MUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1ZThhZGFlNDIxMDg3MzM1ODBmNDA4NTgiLCJpYXQiOjE1ODYxNTgzMzYsImV4cCI6MTU4Njc2MzEzNn0.EwLTdRXaibNmcbuqVxzEDSfrW37z3eWYIxAifAUsT5I');
print(DateTime.fromMillisecondsSinceEpoch(parsed.expiresAt * 1000, isUtc: true)); // 2020-04-13 07:32:16.000Z
}
Related
I was trying to create a function to make a GET with query parameters. I was dealing with the Mangadex API and was to send a parameter called 'manga' as an array. I created the code as follows:
Future<http.Response> getCoverArtResponse(String mangaID) async {
var queryParameters = {
'limit': '10',
'manga': [mangaID] //Here
};
var unencodedPath = '/cover';
var response = await http.get(
Uri.https(authority, unencodedPath, queryParameters),
headers: {HttpHeaders.contentTypeHeader: 'application/json'});
return response;
}
However, the response was the following error:
{"result":"error","errors":[{"id":"9c346772-7b14-5982-b4b6-7b5888522762","status":400,"title":"validation_exception","detail":"Error validating \/manga: String value found, but an array is required","context":null}]}
How am I supposed to send the parameters? So far I have tried -
'manga': [mangaID]
'manga': '[$mangaID]'
None of them seem to work.
import 'dart:async';
import 'package:wnetworking/wnetworking.dart';
class MangaDex {
static const _base = 'https://api.mangadex.org';
static FutureOr<void> _getter({required String url, required Function(JMap item, int idx) onItem}) async {
await HttpReqService.getJson<JMap>(url)
.then((response) {
var results = response?['results'];
if (results != null) {
if (results is List) {
var i = 0;
results.forEach((manga) => onItem(manga, ++i));
} else {
print(response);
}
}
});
}
static FutureOr<void> cover({int limit = 10, int offset=0, String? mangaId, String? coverId}) async {
final mangas = mangaId != null ? '&manga[]=$mangaId' : '';
final covers = coverId != null ? '&ids[]=$coverId' : '';
final url = '$_base/cover?limit=$limit&offset=$offset$mangas$covers';
await _getter(
url: url,
onItem: (item, idx) {
print('$idx) "${item['data']?['attributes']?['fileName']}"');
print(' id: ${item['data']?['id']}\n');
},
);
}
}
void main(List<String> args) async {
await MangaDex.cover(mangaId: '32d76d19-8a05-4db0-9fc2-e0b0648fe9d0', limit: 2);
print('\nJob done');
}
Result:
1) "f5873770-80a4-470e-a11c-63b709d87eb3.jpg"
id: b6c7ce9c-e671-4f26-90b0-e592188e9cd6
2) "e9f926db-b469-48c4-8cc4-a8e523ad75ca.jpg"
id: 00aae6e0-46bb-4f92-a82a-1c740789b704
Job done
Replace wnetworking package with http package, and JMap with Map<String, dynamic>
NOTE: MangaDex Documentation is lacking and misleading about how to correctly use its endpoints.
can anyone explain how to decode a token in json using dart.
i done in android with this below code. But how to decode a token in dart.
public class JWTUtils {
public static String decoded(String JWTEncoded) throws Exception {
String encode = "";
try {
String[] split = JWTEncoded.split("\\.");
Log.d("JWT_DECODED", "Header: " + getJson(split[0]));
encode = getJson(split[1]);
} catch (UnsupportedEncodingException e) {
//Error
}
return encode;
}
private static String getJson(String strEncoded) throws UnsupportedEncodingException{
byte[] decodedBytes = Base64.decode(strEncoded, Base64.URL_SAFE);
return new String(decodedBytes, "UTF-8");
}
}
String encodeddata = JWTUtils.decoded(token);
If you is interested in get the public part of token basically you have to split the token by '.' and decode the second part with base64
var text = token.split('.')[1];
var decoded = base64.decode(text);
return utf8.decode(decoded);
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));
}
I have a multiword String that I'd like to convert to a GET request parameter.
I have an API endpoint /search that takes in the parameter query. Now typically your request would look like http://host/search?query=Hello+World.
I have a String Hello World that I'd like to convert to this URL encoded parameter.
Ofcourse, I could just write the logic to break it into words and add a + in between but I was wondering if the URI class could help with this
I'm using Dart's httpClient to make a request.
Future<String> _getJsonData(String queryToSearch) async {
List data = new List();
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(
config['API_ENDPOINT'] + '/search?query=' +
queryToSearch));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var jsonString = await response.transform(utf8.decoder).join();
data = json.decode(jsonString);
print(data[0]);
return data[0].toString();
} else {
return "{}";
}
}
Essentially, need to encode queryToSearch as the URL parameter.
You can use Uri.http(s) which wrap everythings (query, host, and path) together and encode them accordingly.
final uri = new Uri.http(config['API_ENDPOINT'], '/search', {"query": queryToSearch});
The Uri class provides methods for that
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeQueryComponent.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeFull.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeComponent.html
You can use Uri.parse(url_string) if you have the full URL in this way.
final String accountEndPoint = 'https://api.npoint.io/2e4ef87d9ewqf01e481e';
Future<Account> getAccountData() async {
try {
final uri = Uri.parse(accountEndPoint); // <===
final response = await http.get(uri);
if (response.statusCode == 200) {
Map<String, dynamic> accountJson = jsonDecode(response.body);
return Future.value(Account.fromJson(accountJson));
} else {
throw Exception('Failed to get account');
}
} catch (e) {
return Future.error(e);
}
}
I need to use OAuth 2.0 for accessing user's data.
I have used glassfish security oauth 2 library to implement OAuth 2 client.
I am not sure how can I get code and state values after user granted permission to access the data.
ClientIdentifier clientIdentifier = new ClientIdentifier(clientId, secret);
OAuth2CodeGrantFlow.Builder builder =
OAuth2ClientSupport.authorizationCodeGrantFlowBuilder(clientIdentifier,
HOST_NAME + "/authorize",
HOST_NAME + "/token");
OAuth2CodeGrantFlow flow = builder
.scope("activity")
.redirectUri("http://example.com/#/")
.build();
String authorizationUri = flow.start();
System.out.println(authorizationUri);
String redirectedUrl = getFinalRedirectedUrl(authorizationUri);
System.out.print("Enter the authorization code: ");
String code = "";
String state = "";
try {
code = IN.readLine();
state = IN.readLine();
} catch (final IOException ex) {
throw new RuntimeException(ex);
}
final TokenResult result = flow.finish(code, state);
System.out.println("Access Token: " + result.getAllProperties());
}
For Now, I am taking code and status manually from the redirected url. How Can I automate it.
I tried
public static String getFinalRedirectedUrl(String url) {
String finalRedirectedUrl = url;
try {
HttpURLConnection connection;
do {
connection = (HttpURLConnection) new URL(finalRedirectedUrl).openConnection();
connection.setInstanceFollowRedirects(false);
connection.setUseCaches(false);
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode >= 300 && responseCode < 400) {
String redirectedUrl = connection.getHeaderField("Location");
if (null == redirectedUrl) {
break;
}
finalRedirectedUrl = redirectedUrl;
} else
break;
} while (connection.getResponseCode() != HttpURLConnection.HTTP_OK);
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(finalRedirectedUrl);
return finalRedirectedUrl;
}
but it returns the login page.
I have two classes, a user_api_manager and a base_api_manager. From user_api_manager i call the get method of base_api_manager which performs an http get request and returns a Future<String>. The getrequest is performed but i am not pass the result to my user_api_manager class. The callback result is always null.
This is my user_api_manager.dart
static Future<Map<String,dynamic>> forgotPasswordAPI(String email) async{
String url = Constants.BASE_URL + Constants.FORGOT_PASSWORD_URL + email;
await BaseApiManager.get(url: url).then((val) {
var response = JSON.decode(val);
var status = response['status'];
String message = '';
print(response);
switch (response['status']) {
case Constants.SUCCESS:
message = Constants.SUCCESS_RESPONSE;
break;
case Constants.SERVER_ERROR:
message = Constants.SERVER_ERROR_MESSAGE;
break;
case Constants.UNAUTHORISED:
message = Constants.UNAUTHORISED_MESSAGE;
break;
}
return {'status':status,'message':message};
});
}
and here is my base_api_manager.dart
static Future<String> get({url : String,
parameters : Map ,
headers: Map }) async {
var client = new http.Client();
Map<String,dynamic> resultJSON;
final c = new Completer();
await client.get(url).then((response) { //response is always null
resultJSON = {
'status' : response.statusCode,
'body' : JSON.decode(response.body)
};
c.complete(resultJSON.toString());
return c.future;
});
}
How to solve this issue?
Move the return c.future outside of the response processing, i.e you want to return this from your get otherwise you will return null.
You can simplify the code. That should make it easier to locate the problem
static Future<String> get({url : String, parameters : Map, headers: Map }) async {
var client = new http.Client();
final response = await client.get(url);
print(response.body);
var resultJSON = {
'status' : response.statusCode,
'body' : JSON.decode(response.body)
};
return resultJSON.toString()
}
What does that code print?