Dart - Request GET with cookie - request

I'm trying to make a get request but I need to put the cookie.
Using the curl works:
curl -v --cookie "sessionid=asdasdasqqwd" <my_site>
But the function below does not bring anything
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart';
...
parseHtml() async {
http.Response response = await http.get (
<my_site>,
headers: {"sessionid": "asdasdasqqwd"}
);
Document document = parser.parse (response.body);
print(document.text);
}
Would there be any way to put the cookie on the get request in Dart?

You could use the http.get(Url, Headers Map) function and manually create your cookies in the header map, but it is easier to make a request with cookies included by using HttpClient:
import 'dart:convert';
import 'dart:io';
import 'package:html/dom.dart';
import 'package:html/parser.dart' as parser;
parseHtml() async {
HttpClient client = new HttpClient();
HttpClientRequest clientRequest =
await client.getUrl(Uri.parse("http: //www.example.com/"));
clientRequest.cookies.add(Cookie("sessionid", "asdasdasqqwd"));
HttpClientResponse clientResponse = await clientRequest.close();
clientResponse.transform(utf8.decoder).listen((body) {
Document document = parser.parse(body);
print(document.text);
});
}

To complement the answer:
import 'dart:convert';
import 'dart:io';
import 'package:html/dom.dart';
import 'package:html/parser.dart' as parser;
parseHtml() async {
HttpClient client = new HttpClient();
HttpClientRequest clientRequest =
await client.getUrl(Uri.parse("http://www.example.com/"));
clientRequest.cookies.add(Cookie("sessionid", "asdasdasqqwd"));
HttpClientResponse clientResponse = await clientRequest.close();
clientResponse.transform(utf8.decoder).listen((body) {
Document document = parser.parse(body);
print(document.text); // null
for(Element element in document.getElementsByClassName('your_class')) {
...
}
});
}
The code above worked perfectly well as well as the code below works perfectly:
parseHtml() async {
http.Response response = await http.get(
'http://www.example.com/',
headers: {'Cookie': 'sessionid=asdasdasqqwd'}
);
Document document = parser.parse(response.body);
print(document.text); // null
for(Element element in document.getElementsByClassName('your_class')) {
...
}
}

I used the following method, in addition to rafaelcb21's answer above:
String stringifyCookies(Map<String, String> cookies) =>
cookies.entries.map((e) => '${e.key}=${e.value}').join('; ');
// Used like so..
http.response response = await http.get(
'https://google.com',
headers: { 'Cookie': stringifyCookies(cookies) });

Related

React Axios instance : How to get Token from redux store to put it on my axios instance

I want to create an instance of Axios to use for my HTTP calls, the problem is the token stored on my redux, I don't know how to get it and put it in my configuration, because UseSelector is a part of the functional component but in my case, I have a javascript configuration like this :
import axios from 'axios';
const axiosClient = axios.create();
axiosClient.defaults.baseURL = 'https://example.com/api/v1';
axiosClient.defaults.headers = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
//All request will wait 2 seconds before timeout
axiosClient.defaults.timeout = 2000;
axiosClient.defaults.withCredentials = true;
Does anyone of you know how to get the Token variable from redux in this case, please?
thank you!
There are multiple ways to do it, and I like the Axios interceptor approach.
const instance = axios.create({
baseURL: "base_url",
});
instance.interceptors.request.use(function (config) {
const token = store.getState()?.user?.userData?.token;
config.headers.Authorization = token;
return config;
});

Rails API + React Frontend - how to make CSRF cookie NOT httponly?

I have a Rails 6 API and a React frontend and I would like to keep verify_authenticity_token on all controller actions.
Backend sets CSRF token as follows in application_controller.rb:
class ApplicationController < ActionController::Base
...
include ActionController::Cookies
after_action :set_csrf_cookie
...
protected
def verified_request?
super || request.headers['X-CSRF-Token'] === cookies['X-CSRF-Token']
end
def set_csrf_cookie
if protect_against_forgery? && current_user
cookies['X-CSRF-Token'] = {
value: form_authenticity_token,
httponly: false
}
end
end
end
Frontend is attempting to use js-cookie to retrieve cookies. I have the following in a cookies.js file:
import Cookies from 'js-cookie'
const getCSRFToken = () => {
window.Cookies = Cookies;
const token = Cookies.get('X-CSRF-Token')
return token
}
export default getCSRFToken
and I call this function when I create an Axios request. The function to build the request takes params like method, url, data, etc.:
export const newAxiosIns = params => {
// params will be a hash of various headers
const defaultParams = {
baseURL: baseUrl,
withCredentials: true,
headers: {
common: {
'X-CSRF-TOKEN': getCSRFToken()
}
}
}
const axiosIns = axios.create(defaultParams)
return axiosIns(params)
}
But the cookies end up being httponly in Chrome:
I wondered if it had to do with the form_authenticity_token, so I made a fake token with a value of 'faker' but that was also not httponly.
Thanks!

How to use generated OpenAPI client inside React?

I have generated my API client with openapi-generator-cli generate -i https://linktomybackendswagger/swagger.json -g typescript-axios -o src/components/api --additional-properties=supportsES6=true
Now I have all the files inside my project but I have no clue how to implement this.
How do I instantiate the API? Where do I configure the access token to be used? How do I know each method name for an endpoint?
After 2 hours of googling I can't seem to find a documentation for what seems like the most basic setup questions. Maybe I'm just looking in the wrong places. Can someone point me in the right direction?
Ok, so I figured out a way that I think is clean that I will document here for others that are going down the same path, which is:
Using an API that is using Authorization: Bearer <Token here>
Created the client with openapi-generator-cli using -g typescript-axios
Using OAS3
Let's say you have an endpoint called UserPolicies. After generating the code via CLI each endpoint will have its own class inside the generated file api.ts with the name extended like so UserPoliciesApi.
For using that endpoint the following setup is required.
Example: Inside UserPolicyList.tsx:
import { UserPoliciesApi } from './components/api/api';
import { Configuration } from './components/api/configuration';
const openapiConfig = new Configuration();
openapiConfig.baseOptions = {
headers: { Authorization: 'Bearer ' + cookies.access_token },
};
const openapi = new UserPoliciesApi(openapiConfig);
Let's assume you want to make a GET call for api/Policies you can do so with:
openapi.userPoliciesGetPolicies.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
Now, what I found inconvenient that with this design is the boilerplate code necessary for making a simple api call. I wanted to be able to simply do one import and already have the access_token setup.
So I created a wrapper class like this MyApi.tsx:
import { Cookies } from 'react-cookie';
import { Configuration } from './components/api/configuration';
class MyApi {
private cookies: Cookies;
constructor() {
this.cookies = new Cookies();
}
private accessToken = () => {
return this.cookies.get('access_token');
};
private configuration = () => {
const openapiConfig = new Configuration();
openapiConfig.baseOptions = {
headers: { Authorization: 'Bearer ' + this.accessToken() },
};
return openapiConfig;
};
public userPoliciesApi = () => {
const api = new UserPoliciesApi(this.configuration());
return api;
};
}
export default MyApi.tsx;
Now I you can easily replace the boilerplate and call with this:
Inside UserPolicyList.tsx:
import { MyApi } from './components/myapi/MyApi.tsx';
const api = new MyApi();
api.userPoliciesApi.userPoliciesGetPolicies.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});

Add cookie to axios interceptor request handler

I'm configuring Axios to always make a request with header Authorization with a value which is in user cookie.
My code:
import axios, { AxiosRequestConfig, AxiosResponse} from 'axios';
import {useCookies} from "react-cookie";
const [cookies] = useCookies(["myToken"]);
const customAxios = axios.create({
baseURL: 'http://localhost/storeApi/',
timeout: 10000,
});
const requestHandler = (request: AxiosRequestConfig) => {
request.headers.Authorization = `Bearer ${cookies.jwtToken}`;
return request;
};
customAxios.interceptors.request.use(
(request) => requestHandler(request)
);
export default customAxios;
But I have an error:
Line 3:19: React Hook "useCookies" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function
How to avoid that?
Since it is a React Hook, you can't use useCookies outside a React component function: to access a cookie, you'll need to read it from document.cookie, or install another package, like cookie.
If you're only using the one cookie, you can probably get away by using w3School's cookie example, (which I've turned into an npm package):
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
Then just do:
const cookie: string = getCookie('myToken');

Serverless lambda function failes in react with CORS

Hi all I have written a serverless lambda API using API gateway, the API works as I expect it to do so while i use POSTMAN. the api used PATCH method to update a record in dynamoDB. I have then implemented axios in my in my React app to make the call to my API. The call fails due to CORS fine, i went over to API gateway and i enabled CORS for that end point by pressing on to the method PATCH going into Method Response and Integration Method added all the response headders
Access-Control-Allow-Headers
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Allow-Methods
deployed the API and does not work. I then tried in my serverless.yml to add cors: true and deploy this didnt work either.
Here is my cod:
Serverless.yml:
setBookVotes:
handler: src/handlers/setBookVotes.handler
events:
- http:
method: PATCH
path: /book/{id}/vote
React:
export const updateVoteCount = (id, vote) => {
return axios.patch(`book/${id}`, {
vote: vote,
});
};
Lambda:
import AWS from "aws-sdk";
import middy from "#middy/core";
import httpJsonBodyParser from "#middy/http-json-body-parser";
import httpEventNormalizer from "#middy/http-event-normalizer";
import httpErrorHandler from "#middy/http-event-normalizer";
const dynamodb = new AWS.DynamoDB.DocumentClient();
async function setBookVotes(event, context) {
const { id } = event.pathParameters;
const { vote } = event.body;
const params = {
TableName: process.env.BOOK_TABLE_NAME,
Key: { id },
UpdateExpression: "set vote = vote + :vote",
ExpressionAttributeValues: {
":vote": vote,
},
ReturnValues: "ALL_NEW",
};
let updatedVotes;
try {
const result = await dynamodb.update(params).promise();
updatedVotes = result.Attributes;
} catch (error) {
console.error(error);
throw new createError.InternalServerError(error);
}
return {
statusCode: 200,
body: JSON.stringify(updatedVotes),
};
}
export const handler = middy(setBookVotes)
.use(httpJsonBodyParser())
.use(httpEventNormalizer())
.use(httpErrorHandler());

Resources