flutter secure storage how to store bearer token? - json

I try to store bearer access token to flutter secure storage. But I only able to access to body part details.
i print jsonDecode(res.body) i can get all the details. but i write await storage.write(key: "token", value: data["access_token"]); i get null return.
How can I access to Body>Data > Accesstoken to get token and storage into secure storage?
var data = jsonDecode(res.body);
await storage.write(key: "token", value: data["access_token"]);
Navigator.pushReplacement(
context, SlideRightRoute(page: ooww()));
break;
enter image description here

The token is inside the key data. So you have to use
var data = jsonDecode(res.body);
await storage.write(key: "token", value: data['data']["access_token"]);

Related

Pass the username and password in URL parameters (Dart & Flutter)

I have a flutter app and I'm using back4app.com and Parse RESTful api to register my users, I have read their docs about logging in users but I dont know how to pass my username and password in URL parameters as JSON encoded :
I tried this method:
Future <void>loginMethod(String username,String password) async {
var url = Uri.parse('https://myshoppingapp.b4a.io/login/$username:$password');
final response = await http.get(url, headers: {
'X-Parse-Application-Id': kParseApplicationId,
'X-Parse-REST-API-Key': kParseRestApiKey,
'Content-Type': 'application/json'
},);
final exData = jsonDecode(response.body);
print(exData);
but I've got some errors
Don't use the GET method while sending your personal data to the server.
GET method data is sent data to the server followed by the URL like append with URL request which will be seen to everyone like below.
var url = Uri.parse('https://myshoppingapp.b4a.io/login/$username:$password');
This is how your personal data can be readable from a URL in a GET Method.
'https://myshoppingapp.b4a.io/login/Mehran#metra.org:abcd12345'
For login requests, we should use the POST method. Because our login data is secure which needs security. When using the POST method the data is sent to the server in a bundle.
Future loginMethod(String username,String password) async {
var res = await http.post(Uri.parse('https://myshoppingapp.b4a.io/login/'),
body: {"username": username, "password": password});
print('res : ${res.body}');
if (res.statusCode == 200){ final exData = jsonDecode(res.body);
print(exData);
return res.body;
} else{
final exData = jsonDecode(res.body);
print(exData);
return res.statusCode;
}
}
for HTTP basic authentication
final loginUrl = Uri(scheme: 'https', host: 'example.com', port: 8080, userInfo: 'username:password')
http.get(loginUrl)
but pass username and password via url is not recommended cause it's not safe.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#access_using_credentials_in_the_url
so you should do it by using post formdata.

How to download media files in WhatsApp API which send users?

I am currently writing a chatbot for WhatsApp.
I use the 360dialog platform, which makes it possible to work with the WhatsApp Business API.
When the client sends a message, I see the following JSON object in the logs of my application:
{
"messages": [
{
"from": "77773336633",
"id": "ABGGd3c1cGY_Ago61ytHsZknvtLv",
"image": {
"id": "ffd23134-2dae-4fed-b5f8-0ce7867b6ddd",
"mime_type": "image/jpeg",
"sha256": "bd02100d961b5a1dbaae1dd645485ebbfeda77b44e82c015f1cf29b05654ccb9"
},
"timestamp": "1605703542",
"type": "image"
}
],
"contacts": [
{
"profile": {
"name": "Nurzhan Nogerbek"
},
"wa_id": "77773336633"
}
]
}
I can't find any information in the documentation about how to download this file.
In my case, I want to upload this image file that the client sends to my file storage.
Please tell me which URL method from the WhatsApp API is responsible for this mechanism?
P.S. At the same time, I can send files to clients. This information is available on the official documentation.
May be it will help, just try, take a look:-
const URL = `https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=1104480873777230&ext=1662705250&hash=ATuMx352sLrhKUegbQZSC8oLl3J5Vy3Z49lO4HwTUKWRYQ`;
const FROM = `video`;
const config = {
method: 'get',
url: URL, //PASS THE URL HERE, WHICH YOU RECEIVED WITH THE HELP OF MEDIA ID
headers: {
'Authorization': `Bearer ${token}`
},
responseType: 'arraybuffer'
};
axios(config)
.then(function (response) {
const ext = response.headers['content-type'].split("/")[1];
fs.writeFileSync(`${FROM}.${ext}`, response.data);
})
.catch(function (error) {
console.log(error);
});
It was very tricky because postman worked, but c# didn't work for me, and I spent two days trying to find the solution and finally did the following code, which works in C#:
using HttpClient _httpClient = new HttpClient();
Uri uri = new Uri(mediaUrl);
var fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmss")}.jpeg";
string filePath = $"Files\\{fileName}";
// NOTE: to save bandwidth, request compressed content
_httpClient.DefaultRequestHeaders.AcceptEncoding.Clear();
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("br"));
// NOTE: accept all languages
_httpClient.DefaultRequestHeaders.AcceptLanguage.Clear();
_httpClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("*"));
// NOTE: accept all media types
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("image/jpeg"));
var productValue = new ProductInfoHeaderValue("ScraperBot", "1.0");
var commentValue = new ProductInfoHeaderValue("(+http://www.API.com/ScraperBot.html)");
_httpClient.DefaultRequestHeaders.UserAgent.Add(productValue);
_httpClient.DefaultRequestHeaders.UserAgent.Add(commentValue);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", {WhatsApp_Access_Token});
HttpResponseMessage response = await _httpClient.GetAsync(uri);
response.EnsureSuccessStatusCode();
var mediaType = response?.Content?.Headers?.ContentType?.MediaType ?? string.Empty;
var imageBytes = await response.Content.ReadAsByteArrayAsync();
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
fs.Write(imageBytes, 0, imageBytes.Length);
}
Here, {WhatsApp_Access_Token} is your Whatsapp API permanent token.
Ping me in a comment, please, if you have any issues or questions.
The official documentation has a session for this in https://developers.facebook.com/docs/whatsapp/api/media.
Basically you must make a GET request to download the media.
curl --request GET \
--url https://waba.360dialog.io/v1/media/{media id} \
--header 'D360-API-KEY: {your api token}'

Upload json object to Google Cloud Storage with Google Apps Script

I'm calling an API in a Google Apps Script. The response is a json object. I'd like to send it to Google Cloud Storage.
Here is the script I wrote so far:
function uploadToGoogleCloudStorage() {
var api_response = '{ "var":"value"}'
var url = 'https://storage.googleapis.com/storage/v1/b/my_bucket_name/o/test?fields=OBJECT'.replace("OBJECT", JSON.stringify(api_response))
var response = UrlFetchApp.fetch(url, {
method: "POST"
});
}
I have the following error Exception: Invalid argument: https://storage.googleapis.com/storage/v1/b/gtm_container_export/o/test?fields="{%20\"var\":\"value\"}"
I didn't find any documentation on how to interact with Google Cloud Storage from Google Apps Script. I'm wondering if UrlFetchApp is the right way to do it or if I should activate a specific service.
Here is a basic example for you - your approach just needs to be modified a bit:
function uploadToGoogleCloudStorage() {
let url = "https://storage.googleapis.com/upload/storage/v1/b/[replace this with your bucket ID]/o?uploadType=media&name=my_test_json.json";
let token = "Bearer [replace this with your oauth token!]";
// this is the content of the document we will create in the bucket
let data = {
'name': 'Bob Smith',
'age': 35,
'pets': ['fido', 'fluffy']
};
let options = {
'method' : 'post',
'headers' : {
'Authorization' : token
},
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
'payload' : JSON.stringify(data)
};
var response = UrlFetchApp.fetch(url, options);
console.log( response.getResponseCode() ); // 200 OK
console.log( response.getContentText() );
}
In this case, the file name in the bucket will be "my_test_json.json", as defined in name=my_test_json.json.
Replace [replace this with your bucket ID] with your bucket ID.
Replace [replace this with your oauth token!] with your oauth token.
If you are not familiar with tokens, that is a fairly large topic, and outside the scope of this question. But in case it helps, here are some very basic notes: To generate a test token, I used the OAuth 2.0 Playground to create a test token. I chose "Cloud Storage API" read/write scope. After step 2, I copy/pasted the access_token string out of the "response" box on the right had side of the page. This string is over 300 characters in length. This is not a production-strength solution - it's just for testing.

How do I get a new Access Token before its expiration after user login with chrome.identity.launchWebAuthFlow?

Sorry if this have been asked before but I've spend the whole day googling without any results.
I'm using Chrome Identity API for a Chrome Extension I'm building for my work (interacting with Google Sheets API), and I'm looking to persist the login for the user but refresh tokens with this API are nowhere to be found.
I first implemented chrome.identity.getAuthToken() and I was able to authorize the request to gSheets API, the problem came when the Access Token expired. I'm aware that calling getAuthToken() again refreshes the token if you call it with interactive: false, but only if the People you're logged in with has the same email you authorized in the initial interaction with the popup, and this is not what I want simply because in my browser I'm logged with my personal email, and I want to authorize the work email for the extension. So, after 1 hour I need to request a new token which will prompt a login popup and this is a poor user experience.
Then I tried with chrome.identity.launchWebAuthFlow() with the endpoint https://accounts.google.com/o/oauth2/v2/auth knowing that launchWebAuthFlow() is for non-Google accounts, and even though it worked well, as far as I know, there is no way to refresh the token after — let's say — 45 minutes to avoid kicking out the user.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
switch (request.type) {
case "login":
let authURL = "https://accounts.google.com/o/oauth2/v2/auth";
const clientId = `<CLIENT_ID>`;
const redirectURL = chrome.identity.getRedirectURL("oauth2");
const auth_params = {
client_id: clientId,
redirect_uri: redirectURL,
response_type: "token",
scope: "https://www.googleapis.com/auth/spreadsheets"
};
const paramString = Object.keys(auth_params)
.map(function(k) {
return k + "=" + auth_params[k];
})
.join("&");
authURL += "?" + paramString;
chrome.identity.launchWebAuthFlow(
{ url: authURL, interactive: true },
function(responseURL) {
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError);
return;
}
if (responseURL) {
const paramsString = responseURL.substring(
responseURL.indexOf("#") + 1
);
const params = new URLSearchParams(paramsString);
const paramsObj = () => {
const obj = {};
for (var entry of params.entries()) {
obj[entry[0]] = entry[1];
}
return obj;
};
const { access_token } = paramsObj();
sendResponse({
access_token
});
} else {
console.log(`${responseURL} defined?`);
}
}
);
return true;
default:
console.log("placeholder");
break;
}
});
I'm willing to ditch Chrome Identity API and use another OAuth2 flow if it means I can improve the user experience for the user.
TL;DR: I want to get a new access token either with Chrome Identity API or any other OAuth2 implementation a few minutes before the previous token expires, while being able to use a Google Account different than the logged in Chrome (People).
I could've edited the previous question, but instead I'm going to answer it:
There's a way to get a new token by issuing a code instead of a token using
access_type=offline and response_type:'code'.
let authURL = 'https://accounts.google.com/o/oauth2/v2/auth';
const redirectURL = chrome.identity.getRedirectURL("oauth2");
const auth_params = {
client_id: clientId,
redirect_uri: redirectURL,
response_type: 'code',
access_type: 'offline',
scope: 'https://www.googleapis.com/auth/spreadsheets',
};
chrome.identity.launchWebAuthFlow({url: authURL, interactive: true}, responseURL => console.log(responseURL))
The response will be a URL:
https://<extension_id>.chromiumapp.org/oauth2?code=4/A<code>#
The code returned can be redeemed for a token that can be used only 1 time. You then send a POST request to https://www.googleapis.com/oauth2/v4/token with the following snippet as the request:
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/A<code>&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https://<extension_id>.chromiumapp.org/oauth2&
grant_type=authorization_code
The response will be a JSON object which you can use for ~1 hour to make requests to Google APIs:
{
"access_token": "<access_token>",
"token_type": "Bearer",
"expires_in": 3578
}
Finally before the access token expires you can call launchWebAuthFlow() with interactive: false and it will return a new code and with that you get a new token.
To get a new token by a code is the wrong way. Instead, a refresh token is designed to get a new token after the old one expired.
Exchange a code for refresh and access tokens.
https://developers.google.com/identity/protocols/oauth2/web-server?hl=en#exchange-authorization-code
Save the refresh token. When the current access token expires, get a new token by the refresh token.
https://developers.google.com/identity/protocols/oauth2/web-server?hl=en#offline
Good luck to coding.

Which calls need an access token in ActiveCollab v5 API

I'm playing with Google Apps Script utilizing the ActiveCollab HTTPS API as a way to link Google Forms to specific projects. I can't figure out where to use the access token in the HTTP request when creating a Task in a project.
Maybe I'm missing it, but which API calls in the documentation require the access token as part of the POST request?
The most basic POST request I've sent was:
var token = // token from authentication
{
"name": "Test task",
"token": token
}
...and it returned a 401 error, saying I wasn't authenticated.
So, I tried:
var token = // token from authentication
{
"name": "Test task",
"username": // my username,
"password": // my password,
"token": token
}
...with the same result. So, which calls require a token and does the token go in the POST payload? Or should it be in the POST options?
Update 3/10/2016
I have added the Authorization parameter to the POST request and am now receiving an invalid token error in the response. I've cleared my cache and reauthorized successfully. My test function is below.
function postTicket() {
// Retrieve the stored token after a successful authorization
var token = PropertiesService.getScriptProperties().getProperty("token");
var data = {
"name": "Testing task"
}
var headers = {
Authorization: 'Bearer ' + token
};
var options = {
"method": "post",
"contentType": "application/json",
"headers": headers,
"payload": JSON.stringify(data)
}
try {
var url = BASE_URL + "/projects/8/tasks";
var response = UrlFetchApp.fetch(url, options);
var json = response.getContentText();
var data = JSON.stringify(json)
Logger.log(data);
} catch (e) {
Logger.log(e);
}
}
The logged error is:
returned code
500.{"type":"ActiveCollab\Authentication\Exception\InvalidTokenException","message":"Authorization
token is not valid","code":0
I had the same problem, but after checking Active Collab SDK code i figured out, that we should use these headers:
var headers = {
'X-Angie-AuthApiToken': token
};
By using this code i'm allowed to create tasks via API.
Token needs to be sent using Authorization HTTP header:
Authorization: Bearer TOKEN_THAT_YOU_GOT_FROM_ACTIVE_COLLAB
This means that you need to send the token as part of request header, not payload. Please check the Google Apps documentation for details (I see that fetch has headers object as one of the arguments, so there is support for this type of interaction built into the platform).