Im using the graphql api endpoint to call the endpoint to retrieve a posts information using the function below.
async function getInstagramData(url: string) {
const postHash = '';
const postAPI = `https://www.instagram.com/graphql/query/?query_hash=${postHash}&variables=${encodeURIComponent(
`{"shortcode":"${getShortcode(url)}"}`
)}`;
console.log(postAPI);
try {
const respone = await axios.get(postAPI);
const json = await respone.data;
if (!json.data) return null;
return json.data['shortcode_media'];
} catch (error) {
console.log(error);
return null;
}
}
This works fine locally but doesn't work on the server as I get a 401 unauthorized. After looking into the response I found
data: {
message: 'Please wait a few minutes before you try again.',
require_login: true,
status: 'fail'
}
My question would be how I should log into the API.
From my understanding, I have two solutions (not sure if any of them are possible)
Call the Login API Endpoint store the cookies that are returned and use them when calling the endpoint above.
Is it possible to use a facebook APP ID in my get request to call the request via my application.
Related
I am working with Next-auth and rtk query. I need that when a request, any, returns a 401 unauthorized error, the page redirects directly to the login. How is it done?
I added 'maxAge: 60' to the [...nextauth].js file and also refetchInterval={30} refetchOnWindowFocus={true} to the component tried to find a similar solution, but it doesn't work
since you're using rtk query, you can update your apiSlice baseQuery function, to check for auth errors and redirect on that, my suggestion is this:
create a base query where you check for the 401 and any other error you want:
// try to execute the req, if it fails logout, and redirect to login.
const baseQueryWithAuth: BaseQueryFn = async (args, api, extraOptions) => {
const result = await baseQuery(args, api, extraOptions);
if (result.error?.status === 403 || result.error?.status === 401) {
// non authorized, then redirect to login page.
// if we have jwt, here u should update the access token
localStorage.removeItem(TOKEN_KEY_IN_LOCAL_STORAGE);
Router.replace('/auth/login');
}
return result;
};
in the snippet above, when I'm referring to token deletion as logout because the token is already invalid in the DB, so I just need to delete it in the front, so no invalidate request is needed.
the mentioned baseQuery can be done like this:
const baseUrl = `${process.env.NEXT_PUBLIC_API_PROTOCOL}://${process.env.NEXT_PUBLIC_API_HOST}/api`;
const TOKEN_KEY_IN_LOCAL_STORAGE = 'SavedToken';
const baseQuery = fetchBaseQuery({
baseUrl,
// credentials: 'include',
prepareHeaders: (headers) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem(TOKEN_KEY_IN_LOCAL_STORAGE);
if (token) {
headers.set('Authorization', token);
} else {
Router.replace('/auth/login');
}
return headers;
},
});
and then now since you have a working base query with auth support, you can use that to create a main rtk query apiSlice for your project:
// create api
export const apiSlice = createApi({
baseQuery: baseQueryWithAuth,
tagTypes: ['tag1', 'tag2', 'tag3'],
endpoints: (_builder) => ({}),
});
I am making a Multi-Purpose API Service and as I got the token in the URL working perfect and authorising as expected with a 200. I've been having issues with the token not authorising with curl command or superagent, as its always return a 401 error.
auth.js
const { DB } = require('../src/Routes/index.js');
module.exports = function auth(req, res, next) {
if(!req.query.apiKey) {
return res.status(401).json({"error": "401 Unauthorized", message: "API Token is missing in the query. You will need to generate a Token and put in the apiKey query."})
} else {
let check = DB.filter(k => k).map(i => i.apiToken);
console.log(check);
let t = check.some(e => e == req.query.apiKey)
if(t !== true)
return res.status(401).json({"error": "401 Unauthorized", message: "The API Key you provided is invalid. Please refer to our Docs () and Generate a Token ()"});
return next();
}
}
This is the middleware for the token, I am using this in my routers so then the token will authenticate. However, if I remove the if statement for checking if an API Token is present. It seem to fix the issue kinda but always authenticates with any key (even ones not saved in the db) and is still not properly fixed.
and an example for requesting endpoint with token on a Discord Command:
const { MessageEmbed } = require("discord.js");
const { get } = require("superagent");
exports.run = async (bot, message, args) => {
const { body } = await get(`https://example.com/generators/3000years`)
.query({ image: message.author.displayAvatarURL({ dynamic: true, size: 2048 }) })
.set("Authorization", `Bearer MY_TOKEN`);
const embed = new MessageEmbed()
.setTitle(`**3000 Years**`)
.attachFiles({ attachment: body, name: "3000years.png" })
.setImage("attachment://3000years.png")
.setColor(`#ed8a5c`);
message.channel.send(embed);
}
You can see that if I authorise with Superagent, it will not work and return a 401 Unauthorised in the console.
I would like to ask why this is doing this and if I did something wrong. Any help is appreciated.
I am having issues with a block of code in my node.js API. I have a simple JWT authentication API that is working as expected in terms of logging in and authentication. Howvever I cannot get express to return a response status other then 200.
If I enter an invalid username or password for the login end point, the response I receive is an empty 200 response, despite the fact the below code executes the catch block, and I return a response of 500 with my error. from the post method. This is getting lost somewhere, and converted to the empty 200 response. On succesfull login the return res.status(200).json.... code returns the correct response.
I have the same issue on all endpoints, all error responses are return as an empty 200 response.
Could any one advise.
app.post('/user/login', async (req, res) => {
const email = req.body.user.email;
const password = req.body.user.password;
try {
const authServiceInstance = new AuthService();
const { user, token } = await authServiceInstance.Login(email, password);
return res.status(200).json({ user, token }).end();
} catch(e) {
console.log('Error in login: ', e);
return res.json(e).status(500).end();
}
})
i have some https Cloud Functions which I want to secure by authorizing the user sending the request.
My function looks like this:
exports.authTester = functions.https.onRequest((req, res) => {
const tokenID = req.get('Authorization').split('Bearer ')[1];
return admin.auth().verifyIDToken(tokenID)
.then((decoded) => res.status(200).send(decoded))
.catch((err) => res.status(401).send(err));
console.log(decoded);
});
Within my App I'm calling the function via Alamofire:
Alamofire.request(url, method: .get).responseString { (response) in
if let dta = response.response?.statusCode{
print(response)
}
}
However, my console logs that the function crashes due to the hint:
"Cannot read property 'split' of undefined
at exports.authTester.functions.https.onRequest (...)"
How can I solve this issue?
ThankĀ“s!
You're getting this error because you aren't invoking your cloud function with the proper command that is to passing the token in the HTTP header.
You'd be doing something like:
let token: String = "Bearer" + ...
let header = ["Authorization": token]
// then you pass your header into Alamofire request
Here is a link to on how to do a POST Request from Alamofire?,
a link from Alamofire Docs
I have a couple of days trying to secure my API Gateway using custom authorizers with the auth0 service. I have my lambda which validates my bearer token, the Lambda does work if I invoke it inside the AWS console and when I create a custom authorizer I can successfully tested with a Bearer token.
When I try to attach the authorizer to my API Gateway methods and test the request with postman and the token provided by auth0 it always returns a 401 status code. I read my logs in CloudWatch and the authorization Lambda it's never triggered whenever I make the HTTP request. I am following this tutorial:
https://auth0.com/docs/integrations/aws-api-gateway/custom-authorizers/
And this is my Authorization lambda code:
Handler:
'use strict';
let jwtManager = require("./jwt_manager");
module.exports.authenticate = (event, context, callback) => {
jwtManager.validate(event, function (error, data) {
if (error) {
if (!error) {
context.fail("Unhandled error");
}
context.fail(error);
}
else {
console.log("SUCCEED");
context.succeed(data);
}
});
};
And this is the jwtManager:
"use strict";
require("dotenv").config({ silent: true });
let jwksClient = require("jwks-rsa");
let jwt = require("jsonwebtoken");
module.exports.validate = function(params, callback) {
var token = validateParams(params);
var client = jwksClient({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 10,
jwksUri: process.env.JWKS_URI
});
var decodedJwt = jwt.decode(token, { complete: true });
var kid = decodedJwt.header.kid;
client.getSigningKey(kid, function(error, data) {
if (error) {
console.log(error);
callback(error);
} else {
var signingKey = data.publicKey || data.rsaPublicKey;
jwt.verify(
token,
signingKey,
{ audience: process.env.AUDIENCE, issuer: process.env.ISSUER },
function(error, decoded) {
if (error) {
console.log("ERROR");
console.log(error);
callback(error);
}
else {
console.log(decoded);
var response = {
principalId: decoded.sub,
policyDocument: getPolicyDocument("Allow", params.methodArn),
context: {
scope: decoded.scope
}
}
console.log(response);
console.log(response.policyDocument);
callback(null, response);
}
}
);
}
});
};
function validateParams(params) {
var token;
if (!params.type || params.type !== "TOKEN") {
throw new Error("Expected 'event.type' parameter to have value TOKEN");
}
var tokenString = params.authorizationToken;
if (!tokenString) {
throw new Error("Expected 'event.authorizationToken' parameter to be set");
}
var match = tokenString.match(/^Bearer (.*)$/);
if (!match || match.length < 2) {
throw new Error(
"Invalid Authorization token - '" +
tokenString +
"' does not match 'Bearer .*'"
);
}
return match[1];
}
function getPolicyDocument(effect, resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17'; // default version
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = [ 'execute-api:Invoke', 'lambda:Invoke'] ; // default action
statementOne.Effect = effect;
statementOne.Resource = resource.split('/')[0] + '/*';
policyDocument.Statement[0] = statementOne;
return policyDocument;
}
Thanks in advance!
I would like to describe how I resolved this issue.
First thing, the custom authorizer always need bearer token in authorizationToken field but from while invoking API Gateway from Postman or any other client you can send the 'Bearer Token' in authorization header, as this is an industry standard, AWS has supported it.
The trick here is in 'Token Source' while configuring the 'custom authorizer'. I have attached an image here where you can configure that 'Token Source' this field describes that the input to custom authorizer is from 'Authorization Header'.
This way, you can still send the token in 'Authorzation' header from postman, and API Gateway would copy it from 'Authorization' header and copy it to 'authorizationToken' input field while invoking custom authorizer lambda.
Hope it's clear. Let me know if you need more details.
When you test an API Gateway with a custom authorizer attached but the auth lambda function never triggered, it is likely due to unsuccessful validation in token header name/ token pattern validation.
I am able to reproduce your issue.
The authorizer can only be triggered IF I change the header name from "Authorization" to "AuthorizationToken" in POSTMAN.
check the token header name I made the authorizer works
I think it is likely a new bug in AWS portal as I noticed they have changed the UI to configure API Gateway Authorizers not long ago.
It is very strange a HTTP request has to send bearer token in a header with name "AuthorizationToken". If your AWS plan allows you to access their technical support, you should alert them about this issue.
In my case, the same error (lambda not triggered, authorizer failing) was due to the fact that I didn't deployed the API yet. I may be wrong, but it seems that for testing an Authorizer, your API has to be deployed at least once.
So, I deployed the API, and the authorizer test began to work.
It isn't triggered this can be due to one of two reasons:
the APIGW authorizer response is cached
your configuration expects the token somewhere else.
In the case of the cache, you'll have to wait until it expires or use a different token. For the point of testing, you could remove the cache. In the latter cases, APIGW authorizers automatically reject requests with missing token when the request does not contain the token in the expected location. In those cases your authorizer is not even used.
You can see in this example the authorizer configuration looks at the Authorization header in the identity sources.
In the case you don't specify the authorization header, then the request is automatically rejected.
The other important part of the request is the Authorizer Type. Your code is validating the event.type to be TOKEN. But TOKEN is the legacy authorizer type. The current best practice is to use REQUEST. This exposes the whole request to your authorizer so that you can directly use the request.headers.Authorization header correctly.
It still isn't obvious the best way to handle this so I generally recommend something like this apigw authorizer library and then combining the parsing that library gives you with handling of the request. An example of how to handle the request can be seen here in an apigw authorizer.