TypeError: Redirected path should match configured path, but got: /callback - firebase

I have deployed the ExpressJs app on firebase function and trying to trigger the express app with an HTTP trigger.
I am trying to authorize my express app with OAUTH2.0 to use QuickBooks API. However, I am getting the following error:
TypeError: Redirected path should match configured path, but got: /callback
at CodeFlow.getToken (/srv/node_modules/client-oauth2/src/client-oauth2.js:597:7)
at /srv/routes/callback.js:12:25
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at next (/srv/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/srv/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at /srv/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
at next (/srv/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/srv/node_modules/express/lib/router/index.js:174:3)
The error is in following file:
callback.js
router.get('/', function (req, res) {
// Verify anti-forgery
console.log("OriginalURL "+req.originalUrl)
console.log("base URL "+req.baseUrl)
// Exchange auth code for access token
tools.intuitAuth.code.getToken(req.originalUrl).then(function (token) { //This is where promise is failing
I am using npm package called "client-oauth2".
client-oauth2.js
if (
typeof options.redirectUri === 'string' &&
typeof url.pathname === 'string' &&
url.pathname !== Url.parse(options.redirectUri).pathname
) {
return Promise.reject(
new TypeError('Redirected path should match configured path, but got: ' + url.pathname) //The source of Error. I am not able to find out the value of options.redirectUri
)
}
Following are my configuration details:
"redirectUri": "us-central1-thematic-runner-245505.cloudfunctions.net/createEstimate/callback"
I have made sure that this URL matches with Quickbooks side redirect URL. In the case of localhost it works just fine.
Localhost URL: http://localhost:5001/thematic-runner-245505/us-central1/createEstimate/
The value of req.originalUrl from callback.js is
OriginalURL /thematic-runner-245505/us-central1/createEstimate/callback?code=AB11585447829JwgpXMEpWOR6irwprMe9Z8aqRoSK4npFDKmte&state=Z0t9yRkl-dWaO2J5sJRDaTB9eZKvyyyVcHYQ&realmId=4620816365002391850
Could somebody help me with this error? I don't know what I am doing wrong in the case of production. The callback URL seems to be fine. Any help would be appreciated.

This isn't a valid URL:
"redirectUri": "us-central1-thematic-runner-245505.cloudfunctions.net/createEstimate/callback"
There's no scheme/protocol portion to that URL (e.g. https://). It should start with https:// but instead you're jumping right into the domain.
It needs to be a valid URL, including the protocol/scheme.

Related

'TypeError: Protocol "http:" not supported. Expected "https:"' error when fetching HTTPS site

I'm trying to use node-fetch to capture the contents of a page, and running into an unexpected error. I checked a similar question but it doesn't seem relevant. I am trying to fetch a HTTPS site using an HTTPS agent and agents, but I'm getting an unexpected error about HTTP. I wonder whether this may be due to redirects, but I can't see anything that would cause it. This only fails for this particular URL (works fine, for example, with https://www.robinhood.com) , and I'm trying to figure out why. Here is a minimal example. I'd note that this uses some certificates I have saved locally, but I'm not sure how necessary that is to reproduce.
//start SO example
var siteURL = "https://robinhood.com/l/privacy";
import path from 'path';
import sslrootcas from 'ssl-root-cas';
const rootCas = sslrootcas.create();
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
rootCas.addFile(path.resolve(__dirname,'intermediate.pem'));
import http from 'node:http';
import https from 'node:https';
import UserAgent from 'user-agents';
const myhttpsAgent = new https.Agent({ca: rootCas});
// const requestcheck = fetch("https://www.google.com", {
const requestcheck = fetch(siteURL, {
method: "GET"
,headers: {"User-Agent": new UserAgent() }
,agent: myhttpsAgent
})
Here is the error I'm getting:
node:internal/errors:477
ErrorCaptureStackTrace(err);
^
TypeError: Protocol "http:" not supported. Expected "https:"
at new NodeError (node:internal/errors:387:5)
at new ClientRequest (node:_http_client:177:11)
at request (node:http:96:10)
at file:///home/app/node_modules/node-fetch/src/index.js:94:20
at new Promise (<anonymous>)
at fetch (file:///home/app/node_modules/node-fetch/src/index.js:49:9)
at ClientRequest.<anonymous> (file:///home/app/node_modules/node-fetch/src/index.js:236:15)
at ClientRequest.emit (node:events:525:35)
at HTTPParser.parserOnIncomingClient [as onIncoming] (node:_http_client:674:27)
at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)
at TLSSocket.socketOnData (node:_http_client:521:22)
at TLSSocket.emit (node:events:525:35)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:289:9)
at TLSSocket.Readable.push (node:internal/streams/readable:228:10)
at TLSWrap.onStreamRead (node:internal/stream_base_commons:190:23) {
code: 'ERR_INVALID_PROTOCOL'
}
I wonder whether this may be due to redirects, but I can't see anything that would cause it.
https://robinhood.com/l/privacy redirects to
https://robinhood.com/us/en/support/articles/privacy-policy which then redirects to
http://robinhood.com/us/en/support/articles/privacy-policy/
The latter URL is plain HTTP and thus the wrong protocol by a https-only user agent.

"error - unhandledRejection: Error: listen EADDRINUSE: address already in use :::3000" when I use Slack Bolt for JavaScript with ngrok and Next.js

Background
We are developing a Slack Bot. This time we are using Bolt for JavaScript (Node.js) provided by Slack, React, Next.js, and ngrok. Here is what each of them does.
Bolt for JavaScript: I don't want to use Slack's bare-bones API, but want to benefit from the function that wraps it.
React: Needed to use Next.js
Next.js: Slack needs a request URL to notify my bot app when events such as mentions occur in Slack, but Next.js makes it easy to create an API endpoint to be set to that URL (e.g. /api/something)
ngrok: In the local development environment, that URL will be http://localhost:3000, so the protocol will be http instead of https. Slack does not allow this, so we need a URL that starts with https that tunnels to the local http://localhost:3000. ngrok provides that easily!
Problem to be solved.
I have already confirmed that if I type #xxxx in a certain workspace in Slack, the event is notified to https://xxxx.jp.ngrok.io/api/slack/events. However, in this API file
app.event("app_mention", async ({ event, say }) => {
.
.
.
}
is not invoked and the following error occurs
error - unhandledRejection: Error: listen EADDRINUSE: address already in use :::3000
I would like to know why and how to resolve this.
Source code
/api/slack/events.ts
import type { NextApiRequest, NextApiResponse } from "next";
require("dotenv").config();
import app from "../../../config/slackAuth";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Unique case for Slack challenge
if (req.body.challenge) return res.status(200).json(req.body);
// Subscribe to 'app_mention' event in your App config
// See https://api.slack.com/tutorials/tracks/responding-to-app-mentions
app.event("app_mention", async ({ event, say }) => {
try {
// Response to the message in the thread where the event was triggered with #${message.user}
// See https://slack.dev/bolt-js/concepts#message-sending
await say({
text: `Hi <#${event.user}>!`,
thread_ts: event.ts,
});
} catch (error) {
await say({
text: `<#${event.user}> ${error.message}.`, // #userName Request failed with status code 429.
thread_ts: event.ts,
});
}
});
(async () => {
// Start this app
await app.start(process.env.PORT || 3000);
console.log("⚡️ Bolt app is running!");
})();
return res.status(404).json({ message: "Unknown event type" });
}
Error code
error - unhandledRejection: Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1331:16)
at listenInCluster (net.js:1379:12)
at Server.listen (net.js:1465:7)
at C:\Users\81906\Documents\slackGpt3\node_modules\#slack\bolt\dist\receivers\HTTPReceiver.js:176:25
at new Promise (<anonymous>)
at HTTPReceiver.start (C:\Users\81906\Documents\slackGpt3\node_modules\#slack\bolt\dist\receivers\HTTPReceiver.js:142:16)
at App.start (C:\Users\81906\Documents\slackGpt3\node_modules\#slack\bolt\dist\App.js:241:30)
at eval (webpack-internal:///(api)/./pages/api/slack/events.ts:69:69)
at handler (webpack-internal:///(api)/./pages/api/slack/events.ts:71:7)
at Object.apiResolver (C:\Users\81906\Documents\slackGpt3\node_modules\next\dist\server\api-utils\node.js:363:15) {
code: 'EADDRINUSE',
errno: -4091,
syscall: 'listen',
address: '::',
port: 3000
}
Issue
Using Slack Bolt for JavaScript with Next.js is not straightforward due to the following reasons:
Running npm run dev in a Next.js project starts a server at localhost:3000.
Running app.start() in Slack Bolt for JavaScript starts a server using Express.js, which also tries to use localhost:3000.
This causes an error because two servers are trying to use the same port.
This information was provided by someone at Slack, and the source can be found at https://github.com/slackapi/bolt-js/issues/1687.
Solution
You can change the port number used by Bolt to, for example, 3001.
However, this will make it difficult for the two servers at localhost:3000 and 3001 to communicate with each other.
The request URL registered in the Slack Bolt for JavaScript console is set to 3000, so events received there will not be able to flow to port 3001.

How to fix Firebase CORS errors in callable functions? [duplicate]

This question already has answers here:
Firebase Callable Function + CORS
(21 answers)
Closed 1 year ago.
I have a problem with Firebase and CORs, apparently it cannot reach the endpoint with errors like:
Access to fetch at
'https://europe-west2-XXX.cloudfunctions.net/fetchChatToken'
from origin 'https://trato.app' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
service.ts:203
POST
https://europe-west2-XXX.cloudfunctions.net/fetchChatToken
net::ERR_FAILED (anonymous) # service.ts:203 ... ...
error.ts:66 Uncaught (in promise) Error: internal
at new t (error.ts:66)
at error.ts:175
at e. (service.ts:276)
at tslib.es6.js:100
at Object.next (tslib.es6.js:81)
at a (tslib.es6.js:71)
I also checked the network tab on dev inspector (chrome) to check if the CORS header is there, i dont see it.
Also, I have been checking firebase functions logs and apparently is not being even invoked, the last line showing is the deployment.
the way that Im using it is this:
Front End side:
const functions = firebaseApp.functions('europe-west2');
export const fetchChatToken = async () => (await functions.httpsCallable('fetchChatToken')()).data;
Functions (Backend) side:
const ensureAuthentication = auth => { if (!auth) throw new HttpsError("unauthenticated", "authentication required"); };
exports.fetchChatToken = functions.region("europe-west2").https.onCall((data, context) => {
ensureAuthentication(context.auth);
try {
const { AccessToken } = twilio.jwt;
const { ChatGrant } = AccessToken;
const grant = new ChatGrant({
serviceSid: conversationsid
});
const token = new AccessToken(accountsid, apikey, apisecret);
token.addGrant(grant);
token.identity = context.auth.uid;
return token.toJwt();
} catch (error) {
console.error(error);
throw new HttpsError("internal", "internal error");
} });
Unfortunately there many reasons possible for this CORS error. If the cloud function returns an "internal" error message it might be due to inconsistent Regions or errors in your cloud function code. My checklist for this error when creating a new cloud function:
Not matched Regions of Firestore-Project, Functions and Client side init cause a CORS Error
internal code errors inside the cloud functions cause this error
new function must be included in cloud function index file (if used)
cloud function name must match the string on client side invocation
delete cloud function in firebase dashboard before deploying new one after error
Make sure the function name referenced in the client is correct, see https://stackoverflow.com/a/62042554/1030246
I got it solved changing it to us, basically removing the region, taking out the 'europe-wes2' region from the function declaration and from the function call it works fine again.
I assume there is some error on the firebase side.

"Handler crashed with error runtime error: invalid memory address or nil pointer dereference", but POSTMAN is ok! Why this happens?

I work with vue and go for frontend and backend respectively. I send post request to my server and get 403 error code message(notAllowed). But in postman I get the objects and is fine.
Vue and Vuex
My axios post request:
const response = await this.$axios.post(`http://localhost:8000/v1/org/${params.organization}/kkms/${params.kkm}/closeShift`,{
headers : {
'token' : this.state.token.value
}});
I know I should also use other properties like 'Content-Type' and etc in headers, but know it works well with only "token" property in the other requests. I want to know whether problem in backend or frontend?
It seems you have a mistake in the axios request.
You are receiving a 403, that means you are not authorized (or sometimes something else, check the comments in the question and down here ).
As can be found in axios docs, the post request looks like this:
axios.post(url[, data[, config]]).
It accepts the config (so the headers) as THIRD parameter, while you are setting it as second parameter. Add an empty FormData object as second param, and just shift your config to the third param.
const fakeData = new FormData();
const response = await this.$axios.post(`http://localhost:8000/v1/org/${params.organization}/kkms/${params.kkm}/closeShift`,
fakeData,
{
headers : {
'token' : this.state.token.value
}
});

Unit test Actions on Google Dialogflow locally

I'm trying to unit test a DialogflowApp locally by using the firebase shell environment. (in a cli do firebase experimental:functions:shell and then call my methods)
I have followed this guide by google https://firebase.google.com/docs/functions/local-emulator but they don't use the DialogflowApp where the invoked function tries to bind a request object containing intents and parameters like this ->
exports.myFunction = functions.https.onRequest((request, response) => {
const app = new App({ request, response });
function myMethod(app) {
let myArgument = app.getArgument(MY_ARGUMENT);
app.tell('Here we are responding');
}
let actionMap = new Map();
actionMap.set(MYMETHOD_ACTION, myMethod);
app.handleRequest(actionMap);
});
Regardless of what request object I send in the CLI, like this myFunction(require("../test/testdata.json")), the request body object is empty, like this body: {} which means I can't do app.handleRequest() or app.getArgument(). The error message I get is
RESPONSE RECEIVED FROM FUNCTION: 400, Action Error: no matching intent
handler for: null
I thought that if I populated testdata.json with the json request data shown in Actions on Google -> console.actions.google.com -> Simulator it would be valid data but no.
My question is, how can i mock my request data so that I can start unit testing my fullfillment methods locally?
EDIT 1:
firebase > myMethod.post("/").form(require("../test/testdata.json"))
Sent request to function.
firebase > info: User function triggered, starting execution
info: Function crashed
info: TypeError: Cannot destructure property `parameters` of 'undefined' or 'null'.
if we look in dialogflow_app.js we can see this code for fetching an argument value
getArgument (argName) {
debug('getArgument: argName=%s', argName);
if (!argName) {
error('Invalid argument name');
return null;
}
const { parameters } = this.body_.result;
if (parameters && parameters[argName]) {
return parameters[argName];
}
return this.getArgumentCommon(argName);
}
this.body_ is always just empty {}, regardless of how and what I send into the method when running locally.
EDIT 3
firebase > myMethod({method: "post",json: true, body: require("../test/testdata.json")})
Sent request to function.
firebase > info: User function triggered, starting execution
info: Function crashed
info: TypeError: Cannot destructure property parameters of 'undefined' or 'null'.
Invoking a Firebase HTTPS function using the shell requires a different form. It takes the parameters that the request module does, so in order to emulate a webhook, it will be something like this:
myfunction({
method: 'POST',
json: true,
body: require("../test/testdata.json")
});
These three parameters are important:
You need to specify that this is a POST operation
You need to indicate that the body will be JSON. This will send the correct header and won't try to send the body as x-www-form-urlencoded
You need to include the body. As an object is ok because you've set the json parameter to true.

Resources