I am trying to convert a Python app I made some years ago to a (better) NodeJS implementation. The function in question obtains an access token from the Twitter api to attach to future requests, but my implementation returns 403 bad request. Here is a the functional Python implementation..
def get_bearer_header():
uri_token_endpoint = 'https://api.twitter.com/oauth2/token'
key_secret = f"{twitter_creds.CONSUMER_KEY}:{twitter_creds.CONSUMER_KEY_SECRET}".encode('ascii')
b64_encoded_key = base64.b64encode(key_secret)
b64_encoded_key = b64_encoded_key.decode('ascii')
auth_headers = {
'Authorization': 'Basic {}'.format(b64_encoded_key),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
auth_data = {
'grant_type': 'client_credentials'
}
auth_resp = requests.post(uri_token_endpoint, headers=auth_headers, data=auth_data)
bearer_token = auth_resp.json()['access_token']
bearer_header = {
'Accept-Encoding': 'gzip',
'Authorization': 'Bearer {}'.format(bearer_token),
'oauth_consumer_key': twitter_creds.CONSUMER_KEY
}
return bearer_header
and here is the JS implementation so far..
export const getBearerHeader = async () => {
const keyAndSecret = btoa(`${config.twitterApi.consumerKey}:${config.twitterApi.consumerKeySecret}`)
const buff = Buffer.from(keyAndSecret, 'utf-8');
const b64KeyAndSecret = buff.toString('base64');
const body = new URLSearchParams({
'grant_type': 'client_credentials'
})
const url = config.twitterApi.oauthTokenEndpoint
const headers = {
'Authorization': `Basic ${b64KeyAndSecret}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
const resp = await axios.post(url, body, headers)
console.log("RESPONSE.data")
console.log(resp.data)
}
the request looks fine according to twitter docs, but my response says 403!
Any assistance appreciated!
Get Twitter access token v2 by python and node.js code.
To create API Key and Secret from
Twitter Developer Portal
Main idea to use curl commend for getting access token.
POST oauth2/token
Using config.json file
{
"API_KEY" : "Xx7MxxxxxTkzxxxxxq9xxxxxQ",
"API_KEY_SECRET" : "om4QxxxxxPrcPlxxxxxFikDxxxxxoC5mQxxxxxLy7M17xxxxxK"
}
Node.js code
const axios = require('axios')
const config = require('./config.json');
const getAccessToken = async () => {
try {
const resp = await axios.post(
'https://api.twitter.com/oauth2/token',
'',
{
params: {
'grant_type': 'client_credentials'
},
auth: {
username: config.API_KEY,
password: config.API_KEY_SECRET
}
}
);
console.log(resp.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
getAccessToken();
python code
import requests
import json
import ast
def get_access_token():
with open('config.json') as config_file:
data = json.load(config_file)
params = {
'grant_type': 'client_credentials',
}
response = requests.post('https://api.twitter.com/oauth2/token', params=params, auth=(data['API_KEY'], data['API_KEY_SECRET']))
print(response.content)
json_data = ast.literal_eval(response.content.decode("UTF-8"))
return json_data['access_token']
print(get_access_token())
run from terminal
Related
I'm trying to use HERE's RouteMatching API of JavaScript
Current full code is here: https://github.com/code4history/ShibeContour/blob/d7e56a7/here_mapmatcher.js
For authentication, I coded like this:
import properties from "properties"
import hmacSHA256 from 'crypto-js/hmac-sha256.js'
import Base64 from 'crypto-js/enc-base64.js'
import fetch from 'node-fetch'
import {promises as fs} from "node:fs"
const getProps = async () => {
return new Promise((res) => {
properties.parse("./credentials.properties", {path: true}, function (error, data) {
res(data)
})
})
}
const getToken = async (props) => {
const nonce = `${performance.now()}`
const timestamp = Math.floor((new Date()).getTime() / 1000)
const parameters = [
"grant_type=client_credentials",
`oauth_consumer_key=${props["here.access.key.id"]}`,
`oauth_nonce=${nonce}`,
"oauth_signature_method=HMAC-SHA256",
`oauth_timestamp=${timestamp}`,
"oauth_version=1.0"
].join("&")
const encoding_params = encodeURIComponent(parameters)
const base_string = `POST&${encodeURIComponent(props["here.token.endpoint.url"])}&${encoding_params}`
console.log(base_string)
const signing_key = `${props["here.access.key.secret"]}&`
const hmac_digest = encodeURIComponent(Base64.stringify(hmacSHA256(base_string, signing_key)))
const headers = {
"Authorization": `OAuth oauth_consumer_key="${props["here.access.key.id"]}",oauth_nonce="${nonce}",oauth_signature="${hmac_digest}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="${timestamp}",oauth_version="1.0"`,
"Cache-Control": "no-cache",
"Content-Type": "application/x-www-form-urlencoded"
}
const body = `grant_type=client_credentials`
const response = await fetch(props["here.token.endpoint.url"], {
method: 'post',
body,
headers
})
return response.json()
}
This works well, I got authentication token successfully.
Like this:
{
access_token: 'eyJhbGciOiJSUzUxMiIsImN0eSI6IkpXVCIsImlzcyI6IkhFUkUiLCJhaWQiOiJIZ0NSaFV4...',
token_type: 'bearer',
expires_in: 86399,
scope: 'hrn:here:authorization::org...'
}
But even I used this access_token, route matching call causes authentication error.
Code is:
const main = async () => {
const props = await getProps()
const token_data = await getToken(props)
const body = await fs.readFile("gps/8DD83AC3-8B5A-4108-9CC0-2B78CF9936EC.kml", {encoding: "UTF-8"})
const headers = {
"Authorization": `Bearer ${token_data.access_token}`,
"Cache-Control": "no-cache",
"Content-Type": "application/octet-stream"
}
const response = await fetch(`https://routematching.hereapi.com/v8/calculateroute.json?routeMatch=1&mode=fastest;car;traffic:disabled&apiKey=${props["here.access.key.id"]}`, {
method: 'post',
body,
headers
})
const respond = await response.json()
console.log(respond)
}
main()
Error response was like this:
{
error: 'Forbidden',
error_description: 'These credentials do not authorize access'
}
What is wrong?
I can't imagine what is wrong.
Finally I found the reason
API URL is not match.
We can find many candidate urls,
https://fleet.api.here.com/2/calculateroute.json
https://routematching.hereapi.com/v8/calculateroute.json
etc...
but true working url is only
https://routematching.hereapi.com/v8/match/routelinks
which we can find in this document.
https://platform.here.com/services/details/hrn:here:service::olp-here:route-matching-8/api-ref
Once I changed API endpoint to this correct one, it works well.
Whenever I am trying to invoke the "btoa" method, I am not able to use this within my script. I created a variable to store the client id: client_secret in base64. The id and secrets are being retrieved from the ".env" file.
I have also tried to use the Buffer method, but unable to use this as well. I am getting the error "invalid from" in Buffer.
can someone help me?
Please look at the full code,
const client_id = process.env.SPOTIFY_CLIENT_ID;
const client_secret = process.env.SPOTIFY_CLIENT_SECRET;
const refresh_token = process.env.SPOTIFY_REFRESH_TOKEN;
const basic = btoa(`${client_id}:${client_secret}`);
const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`;
const TOP_TRACKS_ENDPOINT = `https://api.spotify.com/v1/me/top/tracks`;
const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;
const getAccessToken = async () => {
const response = await fetch(TOKEN_ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Basic ${basic}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token
})
});
return response.json();
};
export const getNowPlaying = async () => {
const { access_token } = await getAccessToken();
return fetch(NOW_PLAYING_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`
}
});
};
export const getTopTracks = async () => {
const { access_token } = await getAccessToken();
return fetch(TOP_TRACKS_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`
}
});
};
Using the above script I am trying to embed the customized Spotify play on my site. This wrapper is intended to display the top track as well.
Also, whenever I am trying to run the wrapper used to display the top tracks, it displays the following error,
Full code for displaying the top tracks:
import { type NextRequest } from 'next/server';
import { getTopTracks } from 'lib/spotify';
export const config = {
runtime: 'experimental-edge'
};
export default async function handler(req: NextRequest) {
const response = await getTopTracks();
const { items } = await response.json();
const tracks = items.slice(0, 10).map((track) => ({
artist: track.artists.map((_artist) => _artist.name).join(', '),
songUrl: track.external_urls.spotify,
title: track.name
}));
return new Response(JSON.stringify({ tracks }), {
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'public, s-maxage=86400, stale-while-revalidate=43200'
}
});
}
The problem is that you misspelled the Bytes to ASCII function, it is btoa, not btao.
If you are looking to do it the other way around, spell it atob.
During the Oauth process for reddit API, I have gotten stuck at the access token request, getting an error saying 'unsupported_grant_type'. The API documentation says to use grant type 'authorization_code' which is what I have set now. I've tried using a string, URLSearchParams, and formData to correct it thinking that it was the format that was breaking it but nothing has worked.
Here is the function in question:
async function fetchAccessToken(){
console.log("fetching access token...");
const cred = btoa(`${client_id}:${client_secret}`);
var form = new FormData()
form.append('code', authCode)
form.append('grant_type', grantType)
form.append('redirect_uri', redirect_uri)
const response = await fetch('https://ssl.reddit.com/api/v1/access_token', {
method: 'POST',
headers: {
'Content-Type':"application/x-www-form-urlencoded",
'Authorization':`Basic ${cred}`
},
body: form
})
const data = await response.json();
console.log(response.status);//says 200
console.log(data);//says {error: 'unsupported_grant_type'}
}
I've been stuck here for over a week, any help would be appreciated.
I was stuck on a similar issue - ended up using Axios.
Make sure to add a unique 'User-Agent'.
const axios = require("axios").default;
const url = require("url");
async function fetchAccessToken(){
console.log("fetching access token...");
const client_id = "";
const client_secret = "";
const username = "":
const password = "";
const authData = {
grant_type: "password",
username: username,
password: password,
};
const params = new url.URLSearchParams(authData);
const response = await axios({
url: 'https://www.reddit.com/api/v1/access_token',
method: 'POST',
headers: {
'User-Agent': "myApp:V0.1 by Dschaar", //some unique user agent
},
auth: {
username: username,
password: password,
}
params: params
})
console.log(response.data);
}
I use browserify to let me use require() in my javascript code but it generates code that contains net.Socket() which give Uncaught TypeError: net.Socket is not a constructor. in the browser
is there any solution for that?
node version v14.17.4
browserify 17.0.0
this is my main code
tryjson.js
const axios = require('axios');
const InsertToDataBase = require("./InsertToDataBase");
const username = 'admin'
const password = 'admin'
const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64')
const urlLAMP_0 = 'http://127.0.0.1:8282/~/mn-cse/mn-name/LAMP_0/DATA/la'
const urlLAMP_1 = 'http://localhost:8282/~/mn-cse/mn-name/LAMP_1/DATA/la'
function getDataLAMP_0(){
axios.get(urlLAMP_0, {
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin':'*',
"X-M2M-RI":"OM2M-webpage",
'Authorization': `Basic ${token}`,
'Accept': 'application/json',
'mode': 'cors',
'credentials': 'include',
}
})
.then(function(response) {
document.getElementById("rn0").textContent = response.data['m2m:cin'].rn;
document.getElementById("ty0").textContent = response.data['m2m:cin'].ty;
document.getElementById("ri0").textContent = response.data['m2m:cin'].ri;
document.getElementById("pi0").textContent = response.data['m2m:cin'].pi;
document.getElementById("ct0").textContent = response.data['m2m:cin'].ct;
document.getElementById("lt0").textContent = response.data['m2m:cin'].lt;
document.getElementById("st0").textContent = response.data['m2m:cin'].st;
document.getElementById("cnf0").textContent = response.data['m2m:cin'].cnf;
document.getElementById("cs0").textContent = response.data['m2m:cin'].cs;
document.getElementById("con0").textContent = response.data['m2m:cin'].con;
return response;
})
.then((response) => {
var rn0 = response.data["m2m:cin"].rn;
var ty0 = response.data["m2m:cin"].ty;
InsertToDataBase.insertdatatolamp0(0,1);
})
}
function getDataLAMP_1(){
axios.get(urlLAMP_1, {
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin':'*',
"X-M2M-RI":"OM2M-webpage",
'Authorization': `Basic ${token}`,
'Accept': 'application/json',
'mode': 'cors',
'credentials': 'include',
}
})
.then(function(response) {
document.getElementById("rn1").textContent = response.data['m2m:cin'].rn;
document.getElementById("ty1").textContent = response.data['m2m:cin'].ty;
document.getElementById("ri1").textContent = response.data['m2m:cin'].ri;
document.getElementById("pi1").textContent = response.data['m2m:cin'].pi;
document.getElementById("ct1").textContent = response.data['m2m:cin'].ct;
document.getElementById("lt1").textContent = response.data['m2m:cin'].lt;
document.getElementById("st1").textContent = response.data['m2m:cin'].st;
document.getElementById("cnf1").textContent = response.data['m2m:cin'].cnf;
document.getElementById("cs1").textContent = response.data['m2m:cin'].cs;
document.getElementById("con1").textContent = response.data['m2m:cin'].con;
})
}
getDataLAMP_0();
getDataLAMP_1();
setInterval(getDataLAMP_0,100);
setInterval(getDataLAMP_1,100);
InsertToDataBase.js
const {Client} = require('pg')
const client = new Client({
user:"postgres",
password:"admin",
host:"localhost",
port:"5432",
database:"postgres",
})
function insertdatatolamp0(rn0,ty0){
client.connect()
.then(()=>console.log("connected successfuly"))
.then(()=>client.query("insert into lamp0 values ($1,$2)",[rn0,ty0]))
.catch(e=> console.log(e))
.finally(()=> client.end())
}
module.exports = { insertdatatolamp0 };
if i understood correctly, you have two endpoints serving json data and then you will feed a postgres database with it.
however, the InsertToDataBase.js tries to use the postgre sql driver on browser, therefore the error you are seeing.
that code will run fine on node, but not on browser.
since tryjson.js seems to feed a html document while consumes the json endpoints, you either give up the database part or create a small node server to handle those inserts for you.
I'm trying to integrate Auth0.com, and I've written a function that should unlink an identity and then delete it.
The unlinking works, but I keep getting a 403 error when trying to delete the unlinked identity.
The Auth0 API docs (https://auth0.com/docs/api/management/v2#!/Users/delete_users_by_id) say a 403 error is due to either rate limits, insufficient scopes, or user not matching the bearer token.
I think I added the correct scopes to the auth0 client, I'm very sure I'm not hitting rate limits, so it must be the mismatching bearer token.
But I don't understand how that could be?
Can you take a look at what I have and tell me what's gone wrong?
P.S. In case it matters, I'm using auth0-spa.js not the standard auth0.js. More info here.
This is the code I'm working with:
function(properties, context) {
// Load any data
const domain = context.keys.auth0_domain;
const client_id = context.keys.auth0_client_id;
const connection = properties.connection;
const auth0_user_id = properties.auth0_user_id;
//Do the operation
const auth0 = new Auth0Client({
domain: domain,
client_id: client_id,
audience: `https://${domain}/api/v2/`,
scope: "openid email profile read:current_user update:current_user_identities delete:users delete:current_user",
});
const auth0_user_obj = {
id: auth0_user_id
};
const getUserProfile = async (userId) => {
const token = await auth0.getTokenSilently();
const response = await fetch(
`https://${domain}/api/v2/users/${userId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
}
);
return await response.json();
};
const getSecondaryIdentity = async () => {
const auth0user = await getUserProfile(auth0_user_id);
const secondary_identity = auth0user.identities.find(i => i.connection === connection);
return secondary_identity;
}
const unlinkDeleteAccount = async () => {
const secondaryIdentityObj = await getSecondaryIdentity();
const {
provider,
user_id
} = secondaryIdentityObj;
const accessToken = await auth0.getTokenSilently();
const {
sub
} = await auth0.getUser();
await fetch(
`https://${domain}/api/v2/users/${sub}/identities/${provider}/${user_id}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
const secondUserId = provider + '|' + user_id;
await fetch(
`https://${domain}/api/v2/users/${secondUserId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
};
unlinkDeleteAccount();
}