I'm looking for Octokit package and code that is equivalent of exchanging the auth2 app code for a token.
There are so many npm packages for octokit, I'm not even sure which one to look for.
export async function getToken(code:string) {
const url = new URL("https://github.com/login/oauth/access_token");
const queryString = {
client_id: CONFIG.GITHUB_OAUTH_CLIENT_ID,
client_secret: CONFIG.GITHUB_OAUTH_CLIENT_SECRET,
code: code,
};
Object.keys(queryString).forEach((key) =>
url.searchParams.append(key, queryString[key])
);
console.log(url);
const result = await fetch(url);
if (result.ok) {
const tokenQueryString = await result.text();
const tokenObj = convertToJson(tokenQueryString);
return {
token: tokenObj,
/*
access_token: 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&
scope: user:email - TBD url unencode?
token_type:bearer
*/
headers: result.headers.raw(),
/*
application/x-www-form-urlencoded; charset=utf-8
Cache-Control:max-age=0, private, must-revalidate
cookie expiration = 1 year
*/
};
} else {
throw Error("request for token failed: " + result.statusCode);
}
}
Related
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
I create a function that I can log in to my Spotify and get the access token and I create a function to refresh my token but it does not work properly when I pass it to the request function with Axios and it returns 400 or 404.
what should I do ?
here is my code :
const AUTH_URL =
" https://accounts.spotify.com/authorize?client_id=MY_ID&response_type=token&redirect_uri=http://localhost:3000/&scope=user-read-playback-state";
let Login = () => {
const spotifyHandle = (params) => {
const afterHashtag = params.substring(1);
const param = afterHashtag.split("&");
const paramsSplit = param.reduce((Para, currentPara) => {
const [key, value] = currentPara.split("=");
Para[key] = value;
return Para;
}, {});
return paramsSplit;
};
useEffect(() => {
if (window.location.hash) {
const { access_token, expires_in } = spotifyHandle(window.location.hash);
localStorage.clear();
localStorage.setItem("accessToken", access_token);
localStorage.setItem("expiresIn", expires_in);
}
});
return (
<div>
<a href={AUTH_URL}>
<button>Login</button>
</a>
</div>
);
};
here the refresh function:
let refresh = async () => {
const clientId = "id";
const clientSecret = "secret";
const headers = {
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
},
auth: {
username: clientId,
password: clientSecret,
},
};
const data = {
grant_type: "client_credentials",
};
try {
const response = await axios.post(
"https://accounts.spotify.com/api/token",
qs.stringify(data),
headers
);
console.log(response.data.access_token);
return response.data.access_token;
} catch (error) {
console.log(error);
}
};
The Spotify API follows the OAuth 2.0 specs and it requires (as presented at this Spotify's documentation section):
grant_type to be equal to authorization_code
code to be equal to the authorization code returned from the initial request to the Account /authorize endpoint
redirect_uri This parameter is used for validation only (there is no actual redirection). The value of this parameter must exactly match the value of redirect_uri supplied when requesting the authorization code.
And a Authorization is also required at the request header, as stated at the docs:
Base 64 encoded string that contains the client ID and client secret key. The field must have the format: Authorization: Basic *<base64 encoded client_id:client_secret>*
I am writing a javascript program (for a github action) right now but ran into a problem.
I was trying to log into www.overleaf.com and access the page https://www.overleaf.com/project after generating a session cookie by sending a POST request to https://www.overleaf.com/login with my credentials and the csrf token.
The response contained the requested token in the set-cookie header as expected, however, when I tried to access https://www.overleaf.com/project via GET, I get redirected back to https://www.overleaf.com/login
When copying a session cookie saved in my browser, the request works just fine as expected.
I tried doing the same thing in the command line with cURL and it worked there.
I am fairly certain my authentication request is accepted by Overleaf's server, because I have tried intentionally incorrectly sending the password or the csrf token and in both cases, the response does not give me a new session cookie but sends the old one.
If anyone has any clue what is going wrong, I'd be very thankful for your input.
This is what worked in the terminal, which I'm trying to replicate in javascript with node-fetch:
curl -v --header "Content-Type: application/json" --cookie "GCLB=someothercookie;overleaf_session2=firstsessioncookie" --data '{"_csrf":"the_csrf_token", "email": "MYEMAIL", "password":"MYPASSWORD"}' https://www.overleaf.com/login
to get the cookie and csrf token and
curl -v https://www.overleaf.com/project --cookie "overleaf_session2=returnedsessioncookie; GCLB=someothercookie" as the request that returns the html page of my projects.
This is my javascript code, I have double, triple, quadruple checked it but I think I'm missing something.
const fetch = require("node-fetch");
const parser = require("node-html-parser");
const scparser = require("set-cookie-parser");
async function run() {
const email = process.env.EMAIL;
const password = process.env.PASSWORD;
var cookies = await login(email, password);
console.log(await all_projects(cookies));
}
async function login(email, password) {
const login_get = await fetch("https://www.overleaf.com/login");
const get_cookies = login_get.headers.raw()["set-cookie"];
const parsed_get_cookies = scparser.parse(get_cookies, {
decodeValues: false
});
const overleaf_session2_get = parsed_get_cookies.find(
(element) => element.name == "overleaf_session2"
).value;
const gclb = parsed_get_cookies.find(
(element) => element.name == "GCLB"
).value;
console.log("overleaf_session2_get:", overleaf_session2_get, "gclb:", gclb);
const get_responsetext = await login_get.text();
const _csrf = parser
.parse(get_responsetext)
.querySelector("input[name=_csrf]")
.getAttribute("value");
login_json = { _csrf: _csrf, email: email, password: password };
console.log(login_json);
const login_post = await fetch("https://www.overleaf.com/login", {
method: "post",
body: JSON.stringify(login_json),
headers: {
"Content-Type": "application/json",
"Cookie": "GCLB=" + gclb + ";overleaf_session2=" + overleaf_session2_get
}
});
const post_cookies = login_post.headers.raw()["set-cookie"];
const parsed_post_cookies = scparser.parse(post_cookies, {
decodeValues: false
});
const overleaf_session2_post = parsed_post_cookies.find(
(element) => element.name == "overleaf_session2"
).value;
console.log(
"successful:",
overleaf_session2_get != overleaf_session2_post ? "true" : "false"
);
console.log(await fetch("https://www.overleaf.com/project", {
headers: {
"Cookie": "overleaf_session2=" + overleaf_session2_post
}
}))
return "overleaf_session2=" + overleaf_session2_post;
}
async function all_projects(cookies) {
const res = await fetch("https://www.overleaf.com/project", {
headers: {
Cookie: cookies
}
});
return res;
}
run();
Yes your authentication request is probably valid however this is likely to be a security issue which browsers do not allow you to do such thing and freely access another website's cookie.
Browsers do not allow you to access other domain's cookies, If they did then web would be an unsafe place because for example Stackoverflow could access my Facebook account cookie and extract my personal information.
I fixed my issue by not using node-fetch and switching to https.
Here is what worked:
async function login(email, password) {
//GET login page
const get = await get_login();
//get necessary info from response
const csrf = parser
.parse(get.html)
.querySelector(`meta[name="ol-csrfToken"]`)
.getAttribute("content");
const session1 = scparser
.parse(get.headers["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "overleaf_session2").value;
const gclb = scparser
.parse(get.headers["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "GCLB").value;
//POST login data
const post = await post_login(csrf, email, password, session1, gclb);
//get necessary data from response
const session2 = scparser
.parse(post["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "overleaf_session2").value;
//GET new csrf token from project page
const projects = await get_projects(session2, gclb);
const csrf2 = parser
.parse(projects.html)
.querySelector(`meta[name="ol-csrfToken"]`)
.getAttribute("content");
//return data
return {
session: session2,
gclb: gclb,
csrf: csrf2,
projects: projects.html
};
}
async function get_login() {
const url = "https://www.overleaf.com/login";
return new Promise((resolve) => {
https.get(url, (res) => {
var data;
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
resolve({ html: data, headers: res.headers });
});
});
});
}
async function get_projects(session2, gclb) {
const url = "https://www.overleaf.com/project";
return new Promise((resolve) => {
https.get(
url,
{ headers: { Cookie: `GCLB=${gclb};overleaf_session2=${session2}` } },
(res) => {
var data;
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
resolve({ html: data, headers: res.headers });
});
}
);
});
}
async function post_login(_csrf, email, password, session1, gclb) {
const url = "https://www.overleaf.com/login";
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Cookie: `GCLB=${gclb};overleaf_session2=${session1}`
}
};
const postData = {
_csrf: _csrf,
email: email,
password: password
};
return new Promise((resolve) => {
var req = https.request(url, options, (res) => {
resolve(res.headers);
});
req.on("error", (e) => {
console.error(e);
});
req.write(JSON.stringify(postData));
req.end();
});
}
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();
}
I'm writing a node.js script to generate a GitHub installation access token. Here's what I've got:
const axios = require("axios");
var fs = require('fs');
var jwt = require("jsonwebtoken");
var gitInstallationAccessToken = {
genJWTToken: function(callback) {
var private_key = fs.readFileSync("/path/to/my/pemfile.pem");
const now = Math.round(Date.now() / 1000);
const payload = {
iat : now,
exp : now + (10 * 60),
iss : 7233
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256' })
callback(token);
},
genInstallationAccessToken: function(token, callback) {
var jwt = gitInstallationAccessToken.genJWTToken(function(token) {
return token;
});
console.log("JWT: ", jwt)
var instance = axios({
method: "post",
url: "https://api.github.com/installations/:installation_id/access_tokens",
headers: {
"Accept" : "application/vnd.github.machine-man-preview+json",
"Authorization" : `Bearer ${jwt}`
}
})
.then(function(response) {
console.log("Response: ",response.data);
callback(response);
})
.catch(function(error) {
console.warn("Unable to authenticate");
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
if (error.response) {
console.warn(`Status ${error.response.status}`);
console.warn(`${error.response.data.message}`);
}
});
}
}
module.exports = gitInstallationAccessToken;
gitInstallationAccessToken.genInstallationAccessToken(function(response) {
console.log("response: ", response)
});
My JWT token is getting generated by genJWTToken. I can see that if I add a console.log("Token: ", token) before the callback in genJWTToken.
I now need to use that token in genInstallationAccessToken but I'm clearly calling it wrong. As the following returns undefined:
var jwt = gitInstallationAccessToken.genJWTToken(function(token) {
return token;
});
console.log("JWT: ", jwt)
How do I fix this?
I think you should consider refactoring this and use chained promises it will be easier to understand and control..
Something like this:
function getToken() {
return new Promise(function(resolve, reject) {
resolve('token')
})
}
function chainPromise() {
var token
getToken().then((response) => {
token = response
console.log(token)
}).then(() => {
console.log('I am here and also see: ', token)
})
}
chainPromise()
You should then be able to track down the path of your token quite easily