How to validate Google access token locally using google oAuth libraries - node.js

I'm trying to use Google's APIs to modify data on my users' Google account through the use of an id_token for authentication and an access_token to actually use Google's APIs. I know I'm able to verify the authenticity of an id token like such:
import { OAuth2Client } from "google-auth-library";
const client = new OAuth2Client(GOOGLE_CLIENT_ID);
const ticket = await client.verifyIdToken({
token: idToken,
audience: GOOGLE_CLIENT_ID,
});
This verification happens locally on my device without needing to contact Google's servers each time a token needs to be verified.
I tried to figure out how to do the same for the access_token. The top answer on How can I verify a Google authentication API access token? post suggests that I should call an endpoint https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=accessToken to do the verification but that defeats my purpose of trying to do it locally.
What Google OAuth library/method can I use to verify an access token locally. Is it even possible?
Just to reiterate, I'm talking about the access_token, not the id_token.

Related

Authentication with scoped Application-Default credentials failed GCP

Currently I'm struggling with that kind of issue while obtaining an access token for accessing Gmail user mailboxes. I'm trying to get an access token using Google Auth Library for Node.js. using that kind of code snippet:
const {GoogleAuth} = require('google-auth-library');
async function main() {
const auth = new GoogleAuth({
scopes:
'https://mail.google.com/',
});
const client = await auth.getClient();
const token = await auth.getAccessToken();
console.log(client);
console.log(token)
}
main().catch(console.error);
The thing is that I get the access token with the default list of scopes: scope: 'https://www.googleapis.com/auth/cloud-platform openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/accounts.reauth'
When I try to log in with ADC using gcloud auth application-default login --scopes='https://mail.google.com/'
I'm being redirected to the google authentication page to choose the account to provide Google Auth Library access to. As soon as I choose the account there appears the screen with that being shown "The application is blocked"
So, guys, is there a way to grant access to Node.js Google Auth Library client library to Gmail mailboxes of the user authenticated by ADC (Application Default Credentials).
I know about impersonation the service account methods and OAuth2.0 authentication, but is it possible to get access token using scoped ADC? And how to make those ADC customly scoped with (https://mail.google.com) access.

Can an open id connect id token be used to authenticate to an api

I am building a mern application.
the backend built using express exposes an api which users can create data and access the data they have created.
I want to allow users to sign in with google and get authorization to create and access the resources on this api which i control (not on google apis).
I keep coming across oauth 2 / open id connect articles stating that an Id token is for use by a client and a access token provided by a resource server should be used to get access to an api.
e.g. https://auth0.com/blog/why-should-use-accesstokens-to-secure-an-api/
the reason stated for this is that the aud property on the id token wont be correct if used on the api.
I realise that some sources say: that if the spa and api are served from same server and have same client id and therefore audience I can use and id token to authenticate to the api, but I am looking to understand what I can do when this is not the case?
I feel using oauth2 for authorization is overkill for my app and I cant find any information about how to use open id connect to authenticate to my api.
Surely when you sign in to Auth0 authourization server using google it is just requesting an open id connect id token from google?
I am wondering if using Authorization Code Grant flow to receive an id token on the api server would allow me to authenticate a user to my api?
in this case would the api server be the client as far as open id connect is concerned and therefore the aud value would be correct?
I can generate an url to visit the google oauth server using the node googleapis library like so:
const { google } = require("googleapis");
const oauth2Client = new google.auth.OAuth2(
'clientid','clientsecret',
"http://localhost:3000/oauthcallback",//this is where the react app is served from
);
const calendar = google.calendar({ version: "v3", auth: oauth2Client });
const scopes = ["openid"];
const url = oauth2Client.generateAuthUrl({
// 'online' (default) or 'offline' (gets refresh_token)
access_type: "offline",
// If you only need one scope you can pass it as a string
scope: scopes,
});
async function getUrl(req, res) {
console.log(url)
res.status(200).json({
url,
});
}
and use the following flow.
You are not supposed to access any API's using the ID-Token. First of all the life-time of the ID-token is very short, typically like 5 minutes.
You should always use the access-token to access API's and you can using the refresh token get new access-tokens. The ID-token you can only get one time and you use that to create the local user and local cookie session.
If you are using a SPA application, you should also consider using the BFF pattern, to avoid using any tokens in the SPA-Application
see The BFF Pattern (Backend for Frontend): An Introduction
I agree with one of the commenters that you should follow the principle of separation of concern and keep the authorization server as a separate service. Otherwise it will be a pin to debug and troubleshoot when it does not work.

How to decode Google API access token

I have created SPA login using Google api , which returns access_token and id_token
While it is relatively easy to decode the id token using the following code, on a Node.js backend, using google-auth-library:
gapiAuthLibrary.verifyIdToken({
idToken: token,
audience: GOOGLE_OAUTH_TEST_APP_CLIENT_IDD
});
There is no clear way to decode access_token, which is much more reliable.
What do I miss?

Google Actions & Auth0 Account Linking problems

I'm working on my smarthome application for Google Home. I use this library: https://github.com/actions-on-google/actions-on-google-nodejs
For authentication I use Auth0 with Account Linking. This seems to work quiet well but the Bearer token in the Authorization header is malformated (it is not a valid JWT token).
e.g.: "authorization":"Bearer sIuaA9F2N9hn_aVIgVBAb2rcrpl1m8e5"
To validate the jwt-token I want to use jwks-rsa (https://auth0.com/docs/quickstart/backend/nodejs/01-authorization#validate-access-tokens)
So I tried to add the scope id_token in the Account Linking section but I don't receive the correct access token in the header.
So finally my question: How can I make my google application request the correct access token from Auth0?
UPDATE:
To login in I use email/password credentials from auth0.
Account Linking Screenshot
this.app = smarthome({
key: settings.smarthomeKey
});
this.app.onSync(async (body, headers) => {
console.log(JSON.stringify(headers));
return {...};
});
Headers received in the sync function:
{"x-real-ip":"xx.xxx.x.xxx","x-forwarded-for":"xx.xxx.x.xxx","host":"xxxxxxxxxxxxxxxx.localtunnel.me","x-forwarded-proto":"https","x-nginx-proxy":"true","connection":"close","content-length":"79","content-type":"application/json;charset=UTF-8","google-assistant-api-version":"v1","authorization":"Bearer aIxaA9F2N9hn_aVAgVBSb2rcrpl1m8e5","user-agent":"Mozilla/5.0 (compatible; Google-Cloud-Functions/2.1; +http://www.google.com/bot.html)","accept-encoding":"gzip,deflate,br"}

Firebase REST auth when creating token with node.js admin sdk

I know this issue was asked a lot here, but I still cannot seem to find the exact answer that can solve my problem.
I wish to access Firebase using REST calls, by adding an access_token param.
The access_token is created using the Node.js Admin SDK, using the following code:
var admin = require("firebase-admin");
var serviceAccount = require("./pk.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://XXX.firebaseio.com"
});
var uid = "1234";
admin.auth().createCustomToken(uid)
.then(function(customToken) {
// Send token back to client
console.log("Token: "+customToken);
})
.catch(function(error) {
console.log("Error creating custom token:", error);
});
The problem is that if I take the token created from Node.js and use it my REST call, I get an Unauthorized request error.
I have read in some questions that people added the scope param when issuing the token, but have not found a way to do that with Node.js Admin SDK.
Google's docs are not so detailed with this issue. Any idea what I might try to resolve this one?
The token you are using to authenticate to the Firebase REST API is not the correct type of token. You are using a Firebase Auth custom token, which can only be used to authenticate one of the Firebase client SDKs via the signInWithCustomToken() method as explained in Sign in using custom tokens on clients.
In order to authenticate to the Firebase REST API, you have two options: Firebase ID tokens (for user-based access) or Google OAuth2 access tokens (for admin access).
Authenticate with Firebase ID Tokens
See Retrieve ID tokens on the client for an explanation of how to retrieve access tokens in the various Firebase client SDKs. You can also exchange a Firebase custom token for an ID token and refresh token pair via an undocumented REST API:
Endpoint: https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=<API_KEY>
Method: POST
Request Body: { "token": <CUSTOM_TOKEN>, "returnSecureToken": true }
<API_KEY> is the same API key you get from your Firebase Console that you use in the Firebase clients. <CUSTOM_TOKEN> is a Firebase custom token.
Since ID tokens expire after an hour, you will need to use the refresh token to refresh them via this other undocumented REST API:
Endpoint: https://securetoken.googleapis.com/v1/token?key=<API_KEY>
Method: POST
Request Body: { "refresh_token": <REFRESH_TOKEN>, "grant_type": "refresh_token" }
<API_KEY> is the same API key as before. <REFRESH_TOKEN> is the refresh token from the previous API call.
Once you have an ID token, you can pass that to the REST API via the auth query parameter to authenticate a request. The request respects Firebase Security Rules as if the end user logged into the client was making the request.
Authenticate with Google Access Tokens
To authenticate with a Google OAuth2 access token, the first thing you need to do is get one. See Retrieving an access token for an explanation of how to do this. It only currently includes a Java example, but this is possible in many languages, including Node.js. Once you have an ID token, you can pass that to the REST API via the access_token query parameter to authenticate a request. The request will be made with admin access, overriding all Firebase Security Rules and granting full read and write access.

Resources