Can I call Google cloud run with id token client? - node.js

My backend service is deployed on cloud run.
It can only access by authorized request with IAM service account.
So i use google-auth-libray to request from frontend.
const client = await auth.getIdTokenClient(process.env.NEXT_PUBLIC_CALL_URL!);
const data = await client.request({
url: process.env.NEXT_PUBLIC_CALL_URL!,
});
this is my source.
But I want call with my login token.
So i attempt like this.
const client = await auth.getIdTokenClient(process.env.NEXT_PUBLIC_CALL_URL!);
const header = await client.getRequestHeaders();
const data = await axios.get(process.env.NEXT_PUBLIC_CALL_URL, {
header: {
Authorization: `${header}, Bearer mytoken`
}
})
But It's not working.
Can i call request from front-end like this?

Related

How to check wheter the Azure AD token send by React to Node.js is valid

Hi I have a code from https://github.com/Azure-Samples/ms-identity-javascript-react-spa
I changed it a little bit, so instead calling an Microsoft Graph API endpoint, I call mine endpoint on localhost:7000.
So it basically starts with me logging in (here i did not change enything). Then there is this function which acquires token:
const { instance, accounts } = useMsal();
const [graphData, setData] = useState(null);
function RequestProfileData() {
// Silently acquires an access token which is then attached to a request for MS Graph data
instance
.acquireTokenSilent({
...loginRequest,
account: accounts[0],
})
.then((response) => {
callMyEndpoint(response.accessToken).then((response) =>
setData(response)
);
});
}
it uses function callMyEndpoint which looks like this:
export async function callMyEndpoint(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "POST",
headers: headers,
};
return fetch("http://localhost:7000/myendpoint", options)
.then((response) => response.json())
.catch((error) => console.log(error)) // if the user is not logged in- catch an error;
}
Now, onto my Node.js backend application where the http://localhost:7000/myendpoint is served.
app.post("/myendpoint", async (req, res) => {
console.log("TOKEN", req.headers.authorization); // it is being printed here, everything seems fine.
// here i would like to check whether the token is valid
// if req.headers.authorization == AZURE_TOKEN?
// How to do this?
});
And now the question is? How to check in backend if the token send from frontend is valid for the user, so only logged users, or users which are added in my app registration in azure can post onto this request?
You can use the libraries such as validate-azure-ad-token or you can write your own logic using jsonwebtoken
Here I have my custom logic for that first you will need client_id , tenat_id and scope name.
I am assuming you already have client and tenant id and for scope name it will be available in the Expose Api tab of your app registration.
Here I have console app which will take your token and try to validate it.
var jwt = require('jsonwebtoken');
var token = 'your Token';
var clientid = '' ;
var tenantid = "" ;
var scope = "";
// Create an audiance variable
var audiance = 'api://'+clientid;
// decoded token
var decodedToken = jwt.decode(token , {complete :true});
if((decodedToken.payload.aud==audi)&&(decodedToken.payload.scp==scope)&&(decodedToken.payload.tid==tenantid))
{
console.log("The token is valid");
}
else
{
console.log("The Token is invalid")
}
Output :

Authenticating function to function calls for firebase functions on server side

We are using firebase cloud functions in our application. We have 2 firebase functions: 1. A regular firebase cloud function that runs at regular intervals, 2. A firebase http function that is invoked by function #1 and can also be invoked from outside the application environment (in future). We have a use case where we have #1 firebase cloud function processes thousands of user records and performs some specific operations by invoking the #2 firebase http function. Our requirement now is to authenticate the invocation of the firebase http function. Both the firebase functions are in the same service account.
Following the steps in the documentation : https://cloud.google.com/functions/docs/securing/authenticating#authenticating_function_to_function_calls we tried to create an Id token in the calling function and included the ID token in an Authorization: Bearer ID_TOKEN header in the request to the http function.
Our code to obtain the id token. We tried using the firebase receiving function url, our firebase project url
const { URL } = require('url')
const targetAudience = new URL(url)
const client = await auth.getIdTokenClient(targetAudience)
const idToken = await client.request({ url })
Our code to verify the token
const tokenId = request.get('Authorization').split('Bearer ')[1]
const decodedIdToken = await admin.auth().verifyIdToken(tokenId)
We get back an idToken correctly, but when that token is verified, we always get this error :
Error while verifying Firebase ID token: { Error: Firebase ID token has incorrect "aud" (audience) claim. Expected "<firebase-project-name>" but got "https://<cloud-function-endpoint>". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
const targetAudience = new URL(url) - for the target audience we tried the firebase function URL of the http function, the name of the project, adding https to the name of the project, but we always keep getting the same error Firebase ID token has an incorrect "aud" claim
Any pointers on what we could we doing wrong? Has anyone tried to authenticate invocation to one cloud function when the calling function is another cloud function in the same service account.
try to generate the idToken this way
const serviceAccountEmail = '...';
const generateIdToken = async () => {
const tokens = await admin.options.credential?.getAccessToken();
const projectId =
const res = await fetch(`https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${serviceAccountEmail}:generateIdToken`, {
method: 'POST',
headers: {
authorization: `Bearer ${tokens?.access_token}`,
'content-type': 'application/json',
},
body: JSON.stringify({
delegates: [
],
audience: projectId,
includeEmail: true
}),
});
return res.json();
}
Roles needed on the service account
Service Account Token Creator
Service Account User
Google APIs enable on the project
IAM Service Account Credentials API
it seems the admin.auth().verifyToken is expecting the audience to be the projectId instead of the url of the function endpoint.
normally what I do when I want a function to be private(only invoke from other functions) I make it "require authentication(Manage authorized users with Cloud IAM.)" then I don't even have to verify the id token in my implementation.

How to get video call log details from twilio Video in Node.js, on server side?

I want to get video call log details from twilio using node.js on the server side.
I need details:
what time call started/ended,
duration of a call,
A time duration for which each participant connected in a call.
what time each participant joined/left a call.
All the above details for a completed call.
For the above requirements, I found something:
Video Log Analyzer API (beta) on twilio.
But I am not able to understand how can I use this.
There is no SDK provided here. If I try to send a request to the URL then
Curl for this is below
*
curl "https://insights.twilio.com/v1/Video/Rooms"
-u {account_sid}:{auth_token}
But I don't know how to pass details after -u, i.e. where can I send accound_sid and auth_token in my request. I am trying to use axios to send a request to this URL but where can I pass values of accound_sid,auth_token in the request.
What is -u in curl ?
Can anyone provide me some solution for this or any other idea to achieve my rquirement?
I WAS TRYING SOMETHING LIKE THIS
const URL = "https://insights.twilio.com/v1/Video/Rooms/"+room_SID+"/Participants/"+partcipant_SID;
const config = {
headers: {
//'content-type': 'application/json',
//'Authorization': token,
//WHAT TO DO
}
}
axios.get(URL,config)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
The -u is your Twilio Account SID and Twilio Auth Token, you see the field for it on the main page when you log into your Twilio Console.
There are also some other API's:
Video Log Analyzer API (beta)
REST API: Rooms
REST API: Participants
REST API: PublishedTrack
This show active tracks (not when the meeting is completed)
per your comment below, code example:
const axios = require('axios');
const roomSID = 'RM...';
const participantSID = 'PA...';
const ACCOUNT_SID = process.env.ACCOUNT_SID;
const AUTH_TOKEN = process.env.AUTH_TOKEN;
const URL = "https://insights.twilio.com/v1/Video/Rooms/"+roomSID+"/Participants/"+participantSID;
axios({
method: 'get',
url: URL,
auth: {
username: ACCOUNT_SID,
password: AUTH_TOKEN
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});

How to resolve Nodejs google-auth-library invalid token signature error?

I'm using flutter for my mobile app. I try to add sign in with google. Everything is okay for Flutter side. I'm gettin idToken from mobile app and send to my backend, nodejs.
Now, I want to use this idToken to authenticate user's requests on nodejs backend side with google-auth-library package.
let token = "token"
const CLIENT_ID = "client_id"
const { OAuth2Client } = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
try {
const ticket = await client.verifyIdToken({
idToken: token,
audience: CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
});
const payload = ticket.getPayload();
const userid = payload['sub'];
console.log(payload)
} catch (error) {
console.log(error)
}
}
verify()
But this code always returns this error => Error: Invalid token signature:
at OAuth2Client.verifySignedJwtWithCertsAsync (\node_modules\google-auth-library\build\src\auth\oauth2client.js:566:19)
What should I do for to verify this idToken on nodejs backend side?
Thanks.
If the idToken that you are passing to the function is from the log of your flutter app, it is likely that you are not getting the entire idToken printed in the log due to the limitations of print().
I used the below code snippet to print out the idToken and used that in the API which gave me a success response.
print('ID TOKEN');
String token = googleAuth.idToken;
while (token.length > 0) {
int initLength = (token.length >= 500 ? 500 : token.length);
print(token.substring(0, initLength));
int endLength = token.length;
token = token.substring(initLength, endLength);
}

external api handling in the backend

On my express server I make queries to an external API using its own token. When I log in to my server I request a token to the external API based on the user who logged in, and I keep the token of the external API in the token of my express server.
Each user gets different data according to their token from the external api, for queries that require external API information, I read the received token and get the external API token to send it through headers with axios, for example:
const LoginUser = (request, response) {
axios.post('/ExternalApi/auth',request.body)
.then( data =>{
const payload = {
...
tokenExternalApi: data.token
}
const token = jwt.sign(payload, ...)
return response.status(200).json(token)
})
}
const getData = (req, response){
const tokenFromClient = req.headers.authorization
//Function extract tokenExternalApi from payload Token
const tokenExternalApi = getTokenExternl(tokenFromClient )
axios.get(`/urlExternalApi`, { headers:
{ Authorization: tokenExternalApi }}
).then(res => {
return response.status(200).json(res.data)
})
}
Is this the correct approach to managing external apis tokens or is there a cleaner way to do it?
Here is my sample code that I use for hit an external API within function in node js using axios
first time you should install axios npm install axois
const axios = require('axios');
async yourFunction(){
axios({
method: 'POST',
url: "http://yoururl.com",
data: {
name: '+62'+phoneNumber,
number: '+62'+phoneNumber,
message: 'success',
}
});
}
In my personal opinion, this seems to be a clean approach.
But keep in mind that tokens are visible to users, so the fact is your users can decode the token, view tokenExternalApi, know that you are using an external API in the backend and directly make calls to ExternalApi using that token, provided they have the know-how of it. If you understand this fact and are fine with it, then this works.
Otherwise, you can consider encoding the token before sending it to the user or store it on the server-side session.

Resources