how to set more than one cookie in sveltekit endpoint response? - javascript

I'm using sveltekit set-cookie in an endpoint but I'm unable to figure out how to set more than one cookie. I get three cookies back from expressjs server. I need to set the three of them in my endpoint.
I have this endpoint in sveltekit that fetch from an expressjs
import cookie from 'cookie';
export async function post (event) {
const info = await event.request.json()
let email = info.name
let password = info.password
let fetchresults = ""
//fetch from expressjs//
const letscookie = async () => {
let res = await fetch('http://localhost:3000/testcookie',{
method: 'POST',
credentials : 'include',
headers: {
'Accept': 'application/json',
'Content-type' : 'application/json',
},
body: JSON.stringify({
username : email,
password : password
})
})
const data = await res.json()
fetchresults = data
return data
}
let cookieresults = await letscookie()
return {
headers : {
"loginjs-cookieone" : fetchresults.accesstoken,
"loginjs-cookietwo" : fetchresults.refreshtoken,
"x-custom-header": "Whatever",
'set-cookie': cookie.serialize("loginjs", " setcookie_in_loginjs_headers")
},
body : {
//passthistofront,
//results,
cookieresults
}
}
}
My question is how to setup more than one cookie in my headers? if I do
headers : {
"loginjs-cookieone" : fetchresults.accesstoken,
"loginjs-cookietwo" : fetchresults.refreshtoken,
"x-custom-header": "Whatever",
'set-cookie': cookie.serialize("loginjs", " setcookie_in_loginjs_headers"),
'set-cookie' : [cookie.serealize("cookieone", "valueone"), cookie.serealize("cookietwo", "valuetwo")]
},
I get the last cookie set and anything before it is ignored or over written.
So how do I set more than one cookie in my headers using set-cookie?

I removed other set-cookie lines.
Just one set-cookie and put the cookies in an array like this
'set-cookie' : [cookie.serealize("cookieone", "valueone"), cookie.serealize("cookietwo", "valuetwo")]
One set-cookie in headers.

Related

How to set axios header dynamically according to access_token expired and url

I am new to using Axios configuration. **So I am wondering if it is possible to set axios header dynamically?**
Because the end points I am calling right now need a Authentication and different authentication for different api, so I want make a change to the created axios instance’s header when token is expired and with different URL.
Here is my current code:
in config.js
import axios from 'axios'
// to get Authorization for api_1
const {access_token_1} = axios.get('url/access_token_1')
// to get Authorization for api_2
const {access_token_2} = axios.get('url/access_token_2')
export const instance = axios.create({
headers: { Authorization: `Bearer ${access_token_1}` },
})
My Api_1 and 2 call
//Api_1
export const getCountry = async (country: string) => {
const response = await instance.get(
`/sas/${country}`
)
return response.data
}
//Api_2
export const getCity = async (city: string) => {
const response = await instance.get(
`/sps/${city}`
)
return response.data
}
I know header can be set again by certain method, but how could I set it again only when it’s expired and set the instance with right authentication for certain Api
Have a look at this documentation, you can create/update headers and pass them to your axios instance. I think this examples might help a little
axios.defaults.baseURL = 'https://api.example.com';
// Important: If axios is used with multiple domains, the AUTH_TOKEN will be sent to all of them.
// See below for an example using Custom instance defaults instead.
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
axios.get('https://example.com/getSomething', {
headers: {
Authorization: 'Bearer ' + token //the token is a variable which holds the token
}
})

Spotify API Client Credentials Flow returning 400 error

Using Spotify Documentation for Client Credential Flow here:
I was able to create a API request in google app script (Javascript).
function callAPI () {
SPOTIFY_CLIENT_SECRET = secret
SPOTIFY_CLIENT_ID = id
const HEADERS = {
"Content-Type": "application/json",
'Authorization': `Basic ${Utilities.base64Encode(SPOTIFY_CLIENT_ID + ':' + SPOTIFY_CLIENT_SECRET)})`
}
const BODY = {
'grant_type': 'client_credentials'
}
var url = `https://api.spotify.com/api/token`
var requestOptions = {
'method': 'POST',
'headers': HEADERS,
'payload': JSON.stringify(BODY),
'muteHttpExceptions': true,
'redirect': 'follow'
};
var response = UrlFetchApp.fetch(url, requestOptions);
var data = JSON.parse(response.getContentText());
I am confused about two things, please be able to answer both.
1). The Spotify documentation states to enter "Basic" before the client credentials in the authorization header.
Yet, when I run this code, I get this error
{ error:
{ status: 400,
message: 'Only valid bearer authentication supported' } }
If, I'm am using client credential flow, why does it think I am using a bearer token? (Also if I change authentication to Bearer I get a 401 error "Invalid access token")
2). Could you provide an example of a working version of this code and why it was able to run opposed to mine?
I believe your goal is as follows.
You want to convert the following curl command to Google Apps Script.
curl -X "POST" -H "Authorization: Basic ZjM4ZjAw...WY0MzE=" -d grant_type=client_credentials https://accounts.spotify.com/api/token
In this case, grant_type=client_credentials is sent as the form data. When I saw your script, it is sent as the data. And you use the URL of https://api.spotify.com/api/token. But the curl command uses https://accounts.spotify.com/api/token. `I thought that these might be the reason for your issue. So when your script is modified, it becomes as follows.
Modified script:
function callAPI() {
SPOTIFY_CLIENT_SECRET = secret; // Please set your value.
SPOTIFY_CLIENT_ID = id; // Please set your value.
const HEADERS = {
'Authorization': `Basic ${Utilities.base64Encode(SPOTIFY_CLIENT_ID + ':' + SPOTIFY_CLIENT_SECRET)}` // Modified
}
const BODY = {
'grant_type': 'client_credentials'
}
var url = "https://accounts.spotify.com/api/token";
var requestOptions = {
'method': 'POST',
'headers': HEADERS,
'payload': BODY,
'muteHttpExceptions': true,
};
var response = UrlFetchApp.fetch(url, requestOptions);
var data = response.getContentText();
console.log(data)
}
Note:
When I saw your script again, I noticed that Basic ${Utilities.base64Encode(SPOTIFY_CLIENT_ID + ':' + SPOTIFY_CLIENT_SECRET)}) is required to be modified. Because in this case, it's Basic ###). Please remove ).
References:
Client Credentials Flow
fetch(url, params)
I figured it out! For some reason you need to add the client id and client secret in the form data. The Spotify docs says to put them in the headers base64 encoded but that is not the case in this instance. (You don't even need to encode them)
Also you don't even need to include the content-type parameter like the doc says.
working code looks like this
function callAPI () {
let SPOTIFY_CLIENT_SECRET = secret
let SPOTIFY_CLIENT_ID = id
const BODY = {
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'client_credentials',
"client_id": SPOTIFY_CLIENT_ID,
"client_secret": SPOTIFY_CLIENT_SECRET,
}
var url = "https://accounts.spotify.com/api/token";
var requestOptions = {
'method': 'POST',
'payload': BODY,
'muteHttpExceptions': true,
};
var response = UrlFetchApp.fetch(url, requestOptions);
var data = response.getContentText();
console.log(data)
}
I found my answer from reading about a similar problem here

cookies are not sending to the server in nextjs

i have a nextjs app and I'm using expressjs and graphql in backend.
On my ssr page I'm doing:
export async function getServerSideProps(ctx) {
const id = ctx.query.slug[1]
const ad = await fetchCarAd(id, ctx)
return {
props: {
.
.
.
},
}
}
fetchCarAd finally goes here:
const response = await axios(getGraphqlUrl, {
data: data,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
withCredentials: true,
})
in backend i'm doing:
const canBookmarkAd = async (parent, args, context) => {
const user = await ejectUserFromReq(context)
.
.
.
}
export const ejectUserFromReq = async (context) => {
const token = context.cookies && context.cookies.token ? context.cookies.token : null
if (!!!token) {
return null
}
.
.
.
}
Here cookies is empty even when i can see the cookie in chrome developer tools > application > storage or when i navigate to this page from other next pages.
but if i eject cookie from nextjs context and pass to axios as header, it works fine.
// here ctx is comming from nextjs.
const cookie = ctx ? ctx.req.headers.cookie : null;
const response = await axios(getGraphqlUrl, {
data: data,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': getCsrfTokenFromDom(),
'Cookie': cookie || ''
},
withCredentials: true,
})
this solution works but gives us the following error:
because cookie is a forbidden headername
this happens only in getServerSideProps. if i send request after that cookies work fine and there is no need to add cookie to headername.
Anyone knows why cookies are empty or what is the correct way to send cookies in getServerSideProps?.

"grant_type parameter is missing": Spotify API PKCE OAuth Flow Troubles

I'm developing a React app that uses the Spotify API I can't figure out why I'm getting this error when trying to get an access token with the API's PKCE OAuth flow.
{
error: "unsupported_grant_type",
error_description: "grant_type parameter is missing"
}
I'm following the directions from the guide exactly and I'm able to obtain an auth code just fine. Here's my call trying to get the token.
let res = await axios.post("https://accounts.spotify.com/api/token", {}, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
params: {
"grant_type": "authorization_code",
"code": data.code,
"redirect_uri": redirectUri,
"code_verifier": verifier,
"client_id": clientId
}
}).catch(err => console.error(err));
I've tried passing the params in the body of the post request and as url params and both produce the same results. As you can see, I'm clearly providing a grant_type and I'm using the value that the guide said to use.
I've tried every method I was able to find on the internet, nothing seemed to be working, but after a few hours, this succeeded:
const headers = {
Authorization:
'Basic ' +
new Buffer(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64'),
}
const { data } = await axios.post(
'https://accounts.spotify.com/api/token',
'grant_type=client_credentials',
headers: { headers },
)
this.token = data.access_token
After this, you can simply use any endpoint as seen in the Spotify API examples.
Use querystring npm package to parse the data since we're using application/x-www-form-urlencoded in the header
And change the grant_type to grant_type: "client_credentials"
var querystring = require('querystring');
const headers = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}
};
let data = {
grant_type: "client_credentials",
code: data.code,
redirectUri: "http://localhost:8000/callback",
client_id: your_client_id,
client_secret: your_client_secret,
};
we use query.stringify() for the data because the content type is application/x-www-form-urlencoded also don't use params since its a post request
axios
.post(
"https://accounts.spotify.com/api/token",
querystring.stringify(data),
headers
)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
This works for me:
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization:
'Basic ' +
Buffer.from(this.clientId + ':' + this.clientSecret).toString('base64'),
};
this.http.post(
'https://accounts.spotify.com/api/token',
'grant_type=client_credentials',
{ headers },
).subscribe(data => {
console.log(data);
});
I have the same issue, and it's resolved with stringfying request body data
const requestAccessToken = ({
code,
grantType = "authorization_code",
redirectUri = `${APP_BASE_URL}/callback`,
}) => {
const data = qs.stringify({ //query-string library
code,
grant_type: "client_credentials",
redirect_uri: redirectUri,
});
return axios.post(
[SPOTIFY_ACCOUNTS_BASE_URL, SPOTIFY_ACCOUNTS_TOKEN_URI].join(""),
data,
{
headers: {
Authorization: `Basic ${Buffer.from(
`${SPOTIFY_CLIENT_ID}:${SPOTIFY_CLIENT_SECRET}`,
).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
};
Have you traced the message and verified that the request body is definitely as expected? Your OAuth fields look totally correct so I suspect this could just be an axios syntax issue.
I could be wrong but should the 'params' field be called 'data' instead, as in this class of mine.

using twitter api to get token

I am trying to use the twitter api, but need to get authentication. There are 2 types , and I only need Application-only authentication aka app only. This is the type of authentication where an application makes API requests on its own behalf.
The docs explain to use this method, you need to use a bearer token. You can generate a bearer token by passing your consumer key and secret through the POST oauth2 / token endpoint.
Here is the link to docs explaining this endpoint. There is even an example request but still it isn't very clear to me what needs to be done.
I have an API key and API secret key, but am getting the following error:
body: ‘{“errors”:[{“code”:170,“message”:“Missing required parameter:
grant_type”,“label”:“forbidden_missing_parameter”}]}’ }
My server side code looks like this
var request = require('request');
var btoa = require('btoa');
const KEY = encodeURIComponent('1234');
const SECRET = encodeURIComponent('5678');
request({
headers: {
'Authorization': 'Basic ' + btoa(`${KEY}:${SECRET}`),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
uri: 'https://api.twitter.com/oauth2/token',
method: 'POST',
body: JSON.stringify({
'grant_type': 'client_credentials' // I am passing the grant_type here
})
}, function (err, res, body) {
console.log('res', res)
});
The CURL request in the docs looks like the following:
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic eHZ6MWV2R ... o4OERSZHlPZw==
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
To to this there were a couple of things. First the request needed to be made server side. You need to install btoa from npm to provide the encoding of the key and secret key. The KEY and SECRET need to be separated by a colon. The body of the request needs to be a string of
'grant_type=client_credentials'
See full code example below.
const btoa = require('btoa');
request({
headers: {
'Authorization': 'Basic ' + btoa(`${KEY}:${SECRET}`),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
uri: 'https://api.twitter.com/oauth2/token',
method: 'POST',
body: 'grant_type=client_credentials'
}, (error, response, body) => {
const token = JSON.parse(body).access_token;
});
For Swift 5
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
let info = Bundle.main.infoDictionary
let twitterConsumerKey : String = (info?["TwitterConsumerKey"] as? String)!
let twitterConsumerSecret : String = (info?["TwitterConsumerSecret"] as? String)!
let loginString = String(format: "%#:%#", twitterConsumerKey, twitterConsumerSecret)
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()
let urlString = NSString(format: "https://api.twitter.com/oauth2/token");
print("url string is \(urlString)")
let request : NSMutableURLRequest = NSMutableURLRequest()
request.url = NSURL(string: NSString(format: "%#", urlString)as String) as URL?
request.httpMethod = "POST"
request.timeoutInterval = 30
request.httpBody = "grant_type=client_credentials".data(using: String.Encoding.utf8)!
request.addValue("application/x-www-form-urlencoded;charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.addValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
let dataTask = session.dataTask(with: request as URLRequest) {data, response, error -> Void in
guard let httpResponse = response as? HTTPURLResponse,
let receivedData = data else {
print("error: not a valid http response")
return
}
switch (httpResponse.statusCode)
{
case 200:
let response = NSString (data: receivedData, encoding: String.Encoding.utf8.rawValue)
if response == "SUCCESS"
{
}
default:
print("save profile POST request got response \(httpResponse.statusCode)")
let str = String(decoding:data!, as: UTF8.self)
print(str)
}
}
dataTask.resume()
The problem is with the format of http body of request. I was wrongly using dictionary of grant_type : client_credentials instead of string grant_type= client_credentials.
request.httpBody = try! JSONSerialization.data(withJSONObject:
["grant_type" : "client_credentials"], options: [])

Categories