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));
}
Related
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
}
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.
Uploading a single image seems to be no problem with retrofit 2.
However,
i cant figure out how to upload 2 images at the same time.
if followed the documentation:
http://square.github.io/retrofit/2.x/retrofit/retrofit2/http/PartMap.html
File file = new File(path, "theimage");
File file2 = new File(path2, "theimage");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
Map<String, RequestBody> params = new HashMap<>();
params.put("image2", requestBody2 );
Call<ResponseBody> call = service.upload(requestBody, params);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
Log.v("Upload", "success");
}
interface:
public interface FileUploadService {
#Multipart
#POST("/upload")
Call<ResponseBody> upload(
//#Part("image_logo\"; filename=\"image.png\" ") RequestBody file,
#Part("file") RequestBody file,
#PartMap Map<String, RequestBody> params
// #Part("description") String description
);
this gives a 'Upload: success' but on the server side i get gibberish:
CONTENT_TYPE: multipart/form-data;
boundary=50fbfeb3-3abc-4f15-b130-cdcb7e3a0e4f
CONTENT POST:Array (
[file] => �PNG IHDR L alotofbinarygibberish.... ... snip
[file2] => �PNG
IHDR L more binary gibberish...
can anyone point me in the right direction?
single upload does work so thats not the problem, i'm trying to upload 2 or more images.
if i change it to this:
HashMap<String, RequestBody> partMap = new HashMap<String, RequestBody>();
partMap.put("file\"; filename=\"" + file.getName(), requestBody);
partMap.put("file\"; filename=\"" + file2.getName(), requestBody);
Call<ResponseBody> call = service.upload(partMap);
#Multipart
#POST("/upload")
Call<ResponseBody> upload(
#PartMap() Map<String, RequestBody> partMap,
i get no gibberish but only the second image is uploaded... !?
UPDATE
i tried this Retrofit(2.0 beta2) Multipart file upload doesn't work solution but get an error that #body can not me used with multipart:
Java.lang.IllegalArgumentException: #Body parameters cannot be used with form or multi-part encoding. (parameter #1)
for (String key : keys) {
Bitmap bm = selectedImages.get(key);
File f = new File(saveToInternalStorage(bm, key), key);
if (f.exists()) {
buildernew.addFormDataPart(key, key + ".png", RequestBody.create(MEDIA_TYPE, f));
}
}
RequestBody requestBody = buildernew.build();
-
Call<ResponseBody> upload(
#Body RequestBody requestBody
This works:
final MediaType MEDIA_TYPE=MediaType.parse("image/png");
HashMap<String,RequestBody> map=new HashMap<>(selectedImages.size());
RequestBody file=null;
File f=null;
Set<String> keys = selectedImages.keySet();
for (String key : keys) {
try {
Bitmap bitmap = selectedImages.get(key);
f = new File(saveToInternalStorage(bitmap, key), key);
FileOutputStream fos = new FileOutputStream(f);
if(bitmap!=null){
bitmap.compress(Bitmap.CompressFormat.PNG, 0 , fos);
fos.flush();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
return;
}
file=RequestBody.create(MEDIA_TYPE, f);
map.put(""+key+"\"; filename=\""+key+".jpg",file);
Log.i("##MYLOG###", "### MAP PUT:" + key + " filename:"+key+".jpg file:" + file.toString() +" type:"+ file.contentType() );
file=null;
f = null;
}
--
Call<ResponseBody> upload(
#PartMap() Map<String,RequestBody> mapFileAndName //for sending multiple images
--
beware: while debugging this with the httpClient.interceptors() i saw only a single upload but when checking the endpoint itself to see what it actually got, it DID get the multiple uploads!
I might be late but my answer might help future visitors
I am asking user to select multiple images like this:
int PICK_IMAGE_MULTIPLE = 1;
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_MULTIPLE);
Then in onActivityResult() I am doing this:
ArrayList<String> filePaths;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_MULTIPLE) {
if (data != null) {
filePaths=new ArrayList<>();
// If data.getData() == null means multiple images selected, else single image selected.
if (data.getData() == null) {
ClipData clipData = data.getClipData();
if (clipData != null) {
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
Uri uri = item.getUri();
filePaths.add(FileUtils.getPath(Activity.this, uri));
}
}
} else {
filePaths.add(FileUtils.getPath(Activity.this,data.getData()));
}
sendToServer();
}
}
}
You can get FileUtils class from this Github link
My sendToServer() method looks like this:
private void sendToServer() {
if(filePaths!=null) {
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
MediaType MEDIA_TYPE_IMG = MediaType.parse("image/jpeg");
MultipartBody.Builder builder=new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
RequestBody requestBody;
try {
for (int i = 0; i < filePaths.size(); i++) {
File file = new File(filePaths.get(i));
requestBody=RequestBody.create(MEDIA_TYPE_IMG,file);
builder.addFormDataPart("photo"+i,file.getName(),requestBody);
}
RequestBody finalRequestBody=builder.build();
Call<YourResponse> call=apiService.addEvent(finalRequestBody);
call.enqueue(new Callback<YourResponse>() {
#Override
public void onResponse(Call<YourResponse> call, Response<YourResponse> response) {
// process response
}
#Override
public void onFailure(Call<YourResponse> call, Throwable t) {
t.printStackTrace();
t.getCause();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
}
Finally my Retrofit endpoint looks like this:
#POST("event/add")
Call<YourResponse> addEvent(#Body RequestBody body);
Note that YourResponse can be your custom model class for handling response, or you can also use raw Response class in you don't want to make your model class.
Hope this helps new visitors.
Try This
For API:
//Multiple Images
#Multipart
#POST(HttpConstants.FILEMULTIPLEUPLOAD)
Call<Result>uploadMultipleImage(#Part MultipartBody.Part files1,#Part MultipartBody.Part files2, #Query("total_images") int total, #Query("stdID") int stdID);
Client
public class RaytaServiceClass {
public RaytaServiceClass() {
}
private static Retrofit getRetroClient(){
Gson gson = new GsonBuilder()
.setLenient()
.create();
return new Retrofit.Builder()
.baseUrl(HttpConstants.baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
public static RaytaApi getApiService(){
return getRetroClient().create(RaytaApi.class);
}
}
The Call
RaytaApi service= RaytaServiceClass.getApiService();
File file1 = new File(selectedPath1);
File file2 = new File(selectedPath2);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
RequestBody requestFile2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
MultipartBody.Part body =
MultipartBody.Part.createFormData("uploaded_file", file1.getName(), requestFile);
MultipartBody.Part body2 =
MultipartBody.Part.createFormData("uploaded_file", file2.getName(), requestFile2);
Call<Result> resultCall=service.uploadMultipleImage(body,body2,2,1);
Log.v("####WWE","REquest "+resultCall.toString());
Log.v("###WWE","Retrofit Request Method = "+resultCall.request().method());
Log.v("###WWE","Retrofit Request Body = "+resultCall.request().body());
Log.v("###WWE","Retrofit Request Url = "+resultCall.request().url());
final Result[] result = {new Result()};
resultCall.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
progressDialog.dismiss();
Log.v("###WWE","Respnse");
result[0] =response.body();
Log.v("###WWE","Response Result "+result[0].getResult());
if(response.isSuccessful()){
Toast.makeText(UploadMultipleImageActivity.this,"Sucess",Toast.LENGTH_SHORT).show();
Toast.makeText(UploadMultipleImageActivity.this,"Press Refresh Button",Toast.LENGTH_LONG).show();
supportFinishAfterTransition();
}
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
progressDialog.dismiss();
Log.v("###WWE","Failure ");
Log.v("###WWE","MEssage "+t.getMessage());
}
});
Im having difficulties with the HttpConnection posting data to my server. The first time everything goes well. The second time it says; 'Stream already open', but i close everything after the response.
Here is my code:
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.location.*;
import java.io.*;
class GetSnowheights
{
HttpConnection http = null;
QualifiedCoordinates q = null;
public String result = "Geen data";
private boolean running;
public GetSnowheights(QualifiedCoordinates q) {
try
{
/*
this.http = (HttpConnection)Connector.open("http://www.diamond4it.nl/bb/");
this.http.setRequestMethod(HttpConnection.POST);
this.http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
*/
//Internet.getInstance();
this.http = Internet.getConnection();
}catch(Exception err){
err.printStackTrace();
}
this.q = q;
this.result = "Running";
}
public void GetResult(){
StringBuffer sb = new StringBuffer();
this.result = "GetResult";
if(this.http != null){
OutputStream os = null;
InputStream is = null;
try
{
//Send request
os = this.http.openOutputStream();
String data = "lat=1&lng=1";
//String data = "lat=" + this.q.getLatitude() + "&lng=" + this.q.getLongitude();
os.write(data.getBytes());
os.flush();
os.close();
this.result = "dataSend";
//Check response and read data
int res = this.http.getResponseCode();
this.result = "Result: " + res;
if(res == 200){
is = this.http.openInputStream();
int ch;
// Check the Content-Length first
long len = this.http.getLength();
if(len!=-1) {
for(int i = 0;i<len;i++){
if((ch = is.read())!= -1){
sb.append((char)ch);
}
}
} else {
// if the content-length is not available
while ((ch = is.read()) != -1){
sb.append((char)ch);
}
}
is.close();
}
this.result = sb.toString();
}catch(Exception err){
//err.printStackTrace();
this.result = err.toString() + "\r\n" + err.getMessage();
}finally{
if(is != null){
try{
is.close();
}catch(Exception err){
err.printStackTrace();
}
}
if(os != null){
try{
//os.flush();
os.close();
}catch(Exception err){
err.printStackTrace();
}
}
/*
if(http != null){
try{
http.close();
}catch(Exception err){
err.printStackTrace();
}
}
*/
}
}else{
this.result = "No connection";
}
}
}
2 ideas:
Why have you commented out the http.close() in finally block? We should always close HttpConnections.
Don't you call GetResult() from several threads simultaneously? If yes, then make the method synchronized by adding synchronized keyword in its definition.
P.S. I find the design of the class a bit misleading. It's very easy to make a mistake by incorrect usage of it. I'd combine GetSnowheights and GetResult into the only synchronized method.
I tired to connect my app with the remote server and pass few credentials to it, but i am always getting a same response from the server. I tried changing all the parameter value and other request header values that i am passing, but still i can't reach the exact solution. I need to you, whether am i using the correct way to ping with the server and to pass the values.
Below is the code that i am using , Please let me know if i have gone wrong somewhere.
// HttpServiceConnection.java
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.HttpsConnection;
import net.rim.device.api.system.DeviceInfo;
import com.beacon.bb.app.util.WSMConfig;
/**
* #author N********
*
*/
public class HttpServiceCommunication {
public HttpServiceCommunication() {
System.out.println("Http Service Communication Called");
}
public String sendHttpPost(String uri, String email, String uid,
String pass) throws Exception { // Hashtable header
String response = null;
// create the connection...
System.out.println("Url " + uri);
HttpConnection _connection = null;
String params = null;
if (DeviceInfo.isSimulator()) {
params = ";deviceside=false";
} else {
params = ";deviceside=true;interface=wifi";
}
String URL = uri + params;
System.out.println("Connecting to Http Connection ");
try {
_connection = (HttpConnection) Connector.open(URL);
} catch(Exception e){
e.printStackTrace();
}
if (_connection != null) {
_connection.setRequestMethod(HttpConnection.POST);
System.out.println("After Request Method ");
_connection.setRequestProperty("User-Agent",
"Profile/MIDP-2.0 Configuration/CLDC-1.1");
_connection.setRequestProperty("Content-Language", "en-US");
_connection.setRequestProperty("Content-type", "application/json");
// setting header if any
// if (header != null) {
// for (Enumeration en = header.keys(); en.hasMoreElements();) {
// String key = (String) en.nextElement();
// String value = (String) header.get(key);
// _connection.setRequestProperty(key, value);
_connection.setRequestProperty("email", email);
//_connection.setRequestProperty("method","login");
_connection.setRequestProperty("uid", uid);
_connection.setRequestProperty("password", pass);
//_connection.setRequestProperty("uid", uid);
// }
// }
System.out.println("Open Output Stream ");
// System.out.println("Data is "+data);
OutputStream _outputStream = _connection.openOutputStream();
//System.out.println("Writing data ");
//_outputStream.write(data);
// _outputStream.flush(); // Optional, getResponseCode will flush
// Getting the response code will open the connection, send the
// request, and read the HTTP response headers.
// The headers are stored until requested.
try {
System.out.println("Response Code :" + _connection.getResponseCode());
int rc = _connection.getResponseCode();
System.out.println("Response Code :" + rc);
System.out.println("Response Code :" + rc + " if HTTP OK :"
+ (rc == HttpConnection.HTTP_OK));
if (rc == HttpConnection.HTTP_FORBIDDEN) {
System.out.println("FORBIDDEN");
response = WSMConfig.NOT_AUTH;
} else if (rc != HttpConnection.HTTP_OK) {
response = WSMConfig.NOT_OK;
} else if (rc == HttpConnection.HTTP_OK) {
InputStream _inputStream = _connection.openInputStream();
final int MAX_LENGTH = 128;
byte[] buf = new byte[MAX_LENGTH];
int total = 0;
while (total < MAX_LENGTH) {
int count = _inputStream.read(buf, total, MAX_LENGTH
- total);
if (count < 0) {
break;
}
total += count;
}
response = new String(buf, 0, total);
//ByteBuffer bb = new ByteBuffer(_inputStream);
//response = bb.getString();
System.out.println("Response from Server :" + response);
// close everything out
{
if (_inputStream != null)
try {
_inputStream.close();
} catch (Exception e) {
}
if (_outputStream != null)
try {
_outputStream.close();
} catch (Exception e) {
}
if (_connection != null)
try {
_connection.close();
} catch (Exception e) {
}
}
}
else {
response = WSMConfig.SERVER_ERROR;
}
}catch(Exception e){
e.printStackTrace();
}
}
//System.out.println("Response :" + response);
return response;
}
}
I am getting a response like {"code":0,"err":"Missing 'method'."}
Any Help is Appreciable....
Thanks
Try this out when you're wanting to pass data to the server:
//encode your data to send
URLEncodedPostData encoder = new URLEncodedPostData(null, false);
encoder.encode("email", email);
encoder.encode("method", "login");
encoder.encode("uid", uid);
encoder.encode("password", pass);
//Now you open up an output stream to write to the connection
OutputStream os = _connection.openOutputStream();
os.write(encoder.getBytes();
os.flush();
And then continue with the rest of your logic