How to send cookie in flutter graphql calls - flutter

I am working on an Graphql QUERY API which reads domain cookies and based on that return data but when working on flutter app I am not able to send cookies(Which is default in browser). Is there an easier way to send cookies.
Below is my code snippet for Reading cookies from domain. I think there should be some way to set cookies/options in httpLink somehow.
final cookieManager = WebviewCookieManager();
final gotCookies = await cookieManager.getCookies('https://someApp.com');
final HttpLink httpLink = HttpLink(
uri: 'https://someApp.com/graphql',
includeExtensions: true
);
ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(),
link: httpLink,
),
);

Found solution for this. We can set cookie in headers just like below and it works.
HttpLink httpLink = HttpLink(
uri: 'https://apps.cloudhealthtech.com/ui-session',
headers: {'Cookie': 'session_id=ctHB0ZewfasKWBWIUu;'});

Found a solution to pass Browser cookies along GraphQL requests without retrieving them first. It uses the Browser client
import 'package:http/browser_client.dart';
Insert a prepared Http client into the httpLink
var myClient = BrowserClient();
myClient.withCredentials =true;
final httpLink = HttpLink(endpoint +"/graphql",
httpClient: myClient,
// ...
);

Related

Dio dart/Flutter get and set cookie

I would like to do a set cookies, do a get request and after get the cookies.
In python it will be this:
> import requests cookies = {'status': 'working','color':'blue'}
> response = session.get('https://google.com/', cookies=cookies)
> print(session.cookies.get_dict())
Do you know how to flutter it? I tried something like this but it doesn't seem to have a cookie in the response and the cookie doesn't seem to be sent
Map<String, String> headers = {
"status":"working",
"color":"blue"
};
final BaseOptions dioBaseOptions = BaseOptions(
baseUrl: 'https://google.com',
headers: {
'Cookie': headers,
},
);
dio = Dio(dioBaseOptions);
var cookieJar=CookieJar();
dio.interceptors.add(CookieManager(cookieJar));
var response = await dio.get('https://google.com/');
Cookie is set by a server in a response header and a browser sends it back in a request header.
After receiving an HTTP request, a server can send one or more Set-Cookie headers with the response. The browser usually stores the cookie and sends it with requests made to the same server inside a Cookie HTTP header.
See Using HTTP cookies for details.
CookieManager does this for dio and Flutter.
To access Cookies in a dio response
final cookies = response.headers['set-cookie']

Flutter REST api call with Basic auth returns 401, despite correct credentials

I'm trying to call an api from flutter but i keep getting 401 Unauthorized. According to the api documentation it uses basic authentiocation and is UTF-8 encoded. The username and password is provided by the docs and if try the api in a web browser and enter those credentials it goes through and i recieve the data. This is the code i'm using in flutter:
Future<void> requestData() async {
String username = 'abc';
String password = '123';
String basicAuth = 'Basic ' + base64Encode(utf8.encode('$username:$password'));
Response r = await get(
Uri.parse('http://api.example.com'),
headers: {
HttpHeaders.authorizationHeader: basicAuth,
});
print(r.body);
print(r.statusCode);
}
I've also tried this variation which gave the same result:
headers: <String, String>{
'authorization': basicAuth
}
Seeing as the username and password are correct there must be something wrong with how i make the call, but i've tried to do it a bunch of different ways and nothing works. Any help would be greatly appreciated!
As per my experience, there is no need of token or basic auth while doing login. And login is post method not get.
Turns out the documentation i read was outdated/incorrect. The api uses "Digest authentication" which i looked up and was able to implement. This is the code if anyone is interested:
import 'package:http/http.dart';
import 'package:http_auth/http_auth.dart';
...
Response res = await DigestAuthClient("USERNAME", "PASSWORD")
.get(Uri.parse("API_URL")).timeout(const Duration(seconds: 20));

Works via Postman but not in Flutter: API call with GCS pre-signed URL

I'm trying to upload a video file to GCS using a pre-signed url. I've managed to create the url via Google but now I am facing a problem using it.
Upload works in Postman, got response 200.
postman body, postman params
Code copied from Postman results in 403 Forbidden (SignatureDoesNotMatch):
Future<http.StreamedResponse> uploadVideo(
{required String uploadURL, required String filePath}) async {
var headers = {'Content-Type': 'application/octet-stream'};
var request = http.MultipartRequest('PUT', Uri.parse(uploadURL));
request.files.add(await http.MultipartFile.fromPath('file', filePath));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
} else {
print(response.reasonPhrase);
}
return response;
}
This is the error I am getting from Google:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256
20210803T082850Z
20210803/auto/storage/goog4_request
6d513846a3db49f949b0d2eea8f04b90f918b3b94588c3ed55ed3620b7d7e1f6</StringToSign><CanonicalRequest>PUT
/phonedo-interviews/app-test/007/2.mp4
X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=interviews%40interviews-317011.iam.gserviceaccount.com%2F20210803%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210803T082850Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost
content-type:multipart/form-data; boundary=dart-http-boundary-6w1yq6BQN3EkGBrhHZnwidOXZsBecsgSwTT3nBjB9vQCToHt0cg
host:storage.googleapis.com
content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest></Error>
Note: I needed Content-Type to be application/octet-stream so I disabled that header in Postman's automatic headers and added Content-Type manually. When I didn't do that I also got 403.
The solution was to send the file in binary.
Here is the working code:
Future<http.Response> uploadVideo(
{required String uploadURL, required String filePath}) async {
var response = await http.put(
Uri.parse(uploadURL),
headers: {'content-type': 'application/octet-stream'},
body: File(filePath).readAsBytesSync(),
);
In your Postman headers, a Token is given to GCS (first line). Given that you need authorization, Postman probably has this Token saved somewhere application-wise.
In this flutter code, the headers you're giving do not include an Auth token and therefore you're receiving a 403 error.

OAuth invalid_grant error on coinbase using oauth2_client flutter package

I am using the oauth2_client package for flutter, connecting to the Coinbase API via OAuth 2.0.
From what I can tell, Coinbase uses the code flow for authentication. This is the same as Github. This is important to note because I can successfully auth into Github using the oauth2_client package for flutter.
To connect to Github I used the existing client:
import 'package:oauth2_client/oauth2_client.dart';
import 'package:meta/meta.dart';
/// Implements an OAuth2 client against GitHub
///
/// In order to use this client you need to first create a new OAuth2 App in the GittHub Developer Settings (https://github.com/settings/developers)
///
class GitHubOAuth2Client extends OAuth2Client {
GitHubOAuth2Client(
{#required String redirectUri, #required String customUriScheme})
: super(
authorizeUrl: 'https://github.com/login/oauth/authorize',
tokenUrl: 'https://github.com/login/oauth/access_token',
redirectUri: redirectUri,
customUriScheme: customUriScheme) {
accessTokenRequestHeaders = {'Accept': 'application/json'};
}
}
Then I created a method to call within the app:
void _oauthMethod() async {
//clientID
String cID = 'x';
//clientSecret
String cSecret = 'y';
OAuth2Client client = GitHubOAuth2Client(
redirectUri: 'my.app://oauth2redirect', customUriScheme: 'my.app');
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID, clientSecret: cSecret, scopes: ['repo']);
http.Response resp = await http.get('https://api.github.com/user/repos',
headers: {'Authorization': 'Bearer ' + tknResp.accessToken});
}
Calling this function brings up the OAuth page for Github, I can sign in, and if I print resp it shows a list of my repos. As expected.
Using the same method for Coinbase, I first create the new class:
class MyOAuth2Client extends OAuth2Client {
MyOAuth2Client(
{#required String redirectUri, #required String customUriScheme})
: super(
authorizeUrl:
'https://www.coinbase.com/oauth/authorize', //Your service's authorization url
tokenUrl:
'https://api.coinbase.com/oauth/token', //Your service access token url
redirectUri: redirectUri,
customUriScheme: customUriScheme) {
this.accessTokenRequestHeaders = {'Accept': 'application/json'};
}
}
Then I create the method to call:
void _coinbaseAuth() async {
String cID = 'x';
String cSecret = 'y';
MyOAuth2Client client = MyOAuth2Client(
redirectUri: 'my.app://oauth2redirect', customUriScheme: 'my.app');
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID, clientSecret: cSecret, scopes: ['wallet:user:read']);
print(tknResp);
//code fails
//http.Response resp =
// await http.get('https://api.coinbase.com/v2/user', headers: {
// 'Authorization': 'Bearer ' + tknResp.accessToken,
// 'Content-Type': 'application/json',
// 'Charset': 'utf-8'
// });
}
I can't run the http.Response part, because it is filled with nulls. The tknResp prints:
HTTP 401 - invalid_grant The provided authorization grant is invalid,
expired, revoked, does not match the redirection URI used in the
authorization request, or was issued to another client.
I have tried creating a new OAuth application in Coinbase, however this doesn't work.
Does anyone know why I'm getting this error? It's confusing for me as the code worked with Github using the exact same OAuth flow.
I tested the auth flow manually using postman, which enabled me to get the token.
After some testing, I was able to get the token with the dart package by adding the extra auth code params & disabling PKCE
AccessTokenResponse tknResp = await client.getTokenWithAuthCodeFlow(
clientId: cID,
clientSecret: cSecret,
scopes: ["wallet:user:read"],
authCodeParams: {
"grant_type": "authorization_code",
"redirect_uri": "my.app://oauth2redirect"
},
enablePKCE: false,
state: 'OYWjs_95M6jlkvy5');
hi in my case i have problems in the get token with duplicate oauth of coinbase with my app to text.
error "invalid_grant"
To solve, I went to the test account and navigate to the activities section and click x (x) to log out and intend again.
Also applies to other oauth 2
thanks

How i can get Token from headers?

I did authorization via http. post, send a JSON Body with username and password, in the response I get a Header, the Header has a token, it is stored in 'set_cookie: Authorization=token', how do I get it and write it to the storage?
You can get the cookie from the response of login request using the following code
HttpClient _httpClient = new HttpClient();
HttpClientRequest request = await _httpClient.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
print(response.cookies); // this is a List<Cookie>, you can iterate and find the required cookie
Now you can store the cookie using shared_preference plugin, and use it in your all the future requests.
HttpClient client = new HttpClient();
HttpClientRequest clientRequest =
await client.getUrl(Uri.parse("http: //www.example.com/"));
clientRequest.cookies.add(Cookie("sessionid", "asdasdasqqwd"));
You can also explore dio library and use AuthInterceptor to add the token for all the requests for you.