passing properties in callback function nodejs - node.js

I'm using paypal-rest-sdk. Problem I'm facing is, when I'm making an authorizationUrl call, I want to pass some parameters which can be accessed in the redirected URL.
Below is my code
import paypal from 'paypal-rest-sdk';
const openIdConnect = paypal.openIdConnect;
paypal.configure({
mode: "sandbox"
client_id: //MyClientId,
client_secret: //MySecretId,
openid_redirect_uri: `http://myRedirectionEndpoint/account/domestic/paypal/callback?state={accountId:5e8c2291d69ed1407ec86221}`
});
openIdConnect.authorizeUrl({scope: 'openid profile'});
Adding query parameter state gives the error as invalid redirectUri
What is the best way to pass the data that needs to be used after redirection

I think you are slightly misunderstanding how oauth authorization works. Basically if you want to get any data you need to do this AFTER you consume the callback and validate the user in your system as well.
Have you ever seen for Google/github etc openid auth provider returning some data that corresponds to the caller system's data? It's not possible.
You are probably confusing this with webhook where the caller system calls a webhook with some data internally and you capture it. Which is commonly used in payment transactions.
But the auth is slightly different. For auth there are 3 systems.
the actual auth provider (Paypal/google/github) etc.
an Identity provider which basically gets profile data etc and other than for enterprise systems these two systems are simply same.
the caller system which is your NodeJS service in this case.
=> Now caller-system calls the auth provider to get some kind of code generally an auth code. This means the user exists in auth system let's say Google.
=> Then the caller-system calls the identity provider with that auth code checking if the user is there in identity provider(idp) as well and the idp returns access_token, id_token, refresh_token etc (as I said most of the time these are same systems). But consider amazon, let's say you want to login to Amazon with your Google account. You have a Google account alright but you don't have amazon account. So you will get the auth code but will not get the id_token.
=> Now the id_token most of the time contains some basic info of the user in JWT format. But Now the ACCESS_TOKEN is used to do all the other calls to your system(caller system). Now as I said id_token some kind of user data. You can have a db table mapping userid with account number in your NodeJs service.
=> Make an endpoint to get the account number or something which takes access_token and id_token. First validate the access_token and verify the signature of the id_token then decrypt the token to get basic user info. and use that id to fetch the data from your table and use that data.
After Edit:
You can see in the doc:
paypal.configure({
'openid_client_id': 'CLIENT_ID',
'openid_client_secret': 'CLIENT_SECRET',
'openid_redirect_uri': 'http://example.com' });
// Authorize url
paypal.openIdConnect.authorizeUrl({'scope': 'openid profile'});
// Get tokeninfo with Authorize code
paypal.openIdConnect.tokeninfo.create("Replace with authorize code", function(error, tokeninfo){
console.log(tokeninfo);
});
// Get userinfo with Access code
paypal.openIdConnect.userinfo.get("Replace with access_code", function(error, userinfo){
console.log(userinfo);
});
When you get the auth code, you use it to call the paypal.openIdConnect.tokeninfo.create and get the tokens. Then use those tokens to call the paypal.openIdConnect.userinfo.get to get the user Info. Now when you get the userinfo you will be able to create the db row that you wanted to create.
You can add those two below calls in your /callback route.

Related

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 does firebase functions invoker permission works?

I'm trying to secure my firebase functions by using authorization.
I wrote a very simple callable function
exports.hey= functions.https.onCall((data, context) => {
return {hello:"world"};
});
then i deployed to GC and add the permission invoker to allAuthenticatedUsers .
then i went to my app and wrote some test code
FirebaseFunctions.getInstance().getHttpsCallable("hey").call(null).addOnCompleteListener(task -> {
if (task.isSuccessful())
System.out.println(task.getResult().getData());
else
FirebaseCrashlytics.getInstance().recordException(task.getException());
});
This code runs after user authenticateFirebaseAuth.getInstance().signInWithCustomToken(); (I've my own authentication system it works I can see the authenticated user in firebase auth dashboard along with last login the user is able to read database) but the function call always returns http 403
I know that within the function i can use the context to check the auth field and verify if user is authenticated, but what is the point of the permissioning system at all in the GC? if at the end we always need to check the context.auth am i missing something?
W/System.err: com.google.firebase.functions.FirebaseFunctionsException: UNAUTHENTICATED
If the ID token passed to a Cloud Function represents a Google account it works, otherwise, it doesn't.
An authenticated client request for a Google Cloud Functions must have an Authorization: Bearer ID_TOKEN header or ?access_token=ID_TOKEN.
The Authentication header is set with the user’s ID token which is used as a context parameter. A Firebase user’s ID token doesn’t always represent a Google user which makes it incompatible with allAuthenticatedUsers. Because of this you check context.auth. Otherwise you may try with “allUsers” which should work.
You can see this stackoverflow answer for more information.

Using JSON Web Tokens (JWT) with Azure Functions (WITHOUT using Active Directory)

I am sure someone out there has already done this, but I have yet to find any documentation with regard to the Microsoft implementation of JWT. The official documentation from Microsoft for their JWT library is basically an empty page, see:
https://learn.microsoft.com/en-us/dotnet/framework/security/json-web-token-handler-api-reference
So, here is what I (and I am sure many others) would like to accomplish:
Definition: User ID = The username or email address used to log into a system.
AUTHENTICATION:
A user logs in. The user fills in web form and the system sends (via HTTPS POST) the users ID and password (hashed) to the server in order to authenticate / validate the user.
Server Authenticates user. The users ID and password are checked against the values saved in the database and if NOT valid, an invalid login response is returned to the caller.
Create a JWT Token - ???? No documentation available!
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
Given the code below, can anyone provide a code example for steps 3 and 4?
[FunctionName( "authenticate" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get user ID and password from POST data
/*
* Step 2 - Verify user ID and password (compare against DB values)
* If user ID or password is not valid, return Invalid User response
*/
// Step 3 - Create JWT token - ????
// Step 4 - Return JWT token - ????
}
AUTHORIZATION:
Assuming the user was authenticated and now has a JWT token (I am assuming the JWT token is saved in the users session; if someone wants to provide more info, please do):
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
The JWT token is validated - ???? No documentation available!
If the JWT token is NOT valid, a BadRequest response is returned by the function.
If the JWT token is valid, the function uses the data passed to it to process and issue a response.
Given the code below, can anyone provide a code example for steps 1 and 2?
[FunctionName( "do_something" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get JWT token (from POST data or headers?)
// Step 2 - Validate the JWT token - ???
// Step 3 - If JWT token is not valid, return BadRequest response
// Step 4 - Process the request and return data as JSON
}
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Thanks in advance.
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Per my understanding, you could use the related library in your azure function code to generate / validate the JWT token. Here are some tutorials, you could refer to them:
Create and Consume JWT Tokens in C#.
Jwt.Net, a JWT (JSON Web Token) implementation for .NET
JWT Authentication for Asp.Net Web Api
Moreover, you could leverage App Service Authentication / Authorization to configure the function app level Authentication / Authorization. You could go to your Function App Settings, click "NETWORKING > Authentication / Authorization" under the Platform features tab. Enable App Service Authentication and choose Allow Anonymous requests (no action) as follows:
You could create a HttpTrigger function with anonymous accessing for user logging and return the JWT token if the user exists. For the protected REST APIs, you could follow the code sample below:
if(System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated)
{
//TODO: retrieve the username claim
return req.CreateResponse(HttpStatusCode.OK,(System.Security.Claims.ClaimsPrincipal.Current.Identity as ClaimsIdentity).Claims.Select(c => new { key = c.Type, value = c.Value }),"application/json");
}
else
{
return req.CreateResponse(HttpStatusCode.Unauthorized,"Access Denied!");
}
For generating the JWT token used in App Service Authentication, you could follow How to: Use custom authentication for your application and the code under custom API controller CustomAuthController from adrian hall's book about Custom Authentication to create the JWT token.
UPDATE:
For the custom authentication approach under App Service Authentication, I just want op to leverage the authentication / Authorization provided by EasyAuth. I have did some test for this approach and found it could work on my side. Op could send the username and password to the HttpTrigger for authentication, then the HttpTrigger backend need to validate the user info, and use Microsoft.Azure.Mobile.Server.Login package for issuing App Service Authentication token to the client, then the client could retrieve the token from the AuthenticationToken property. The subsequent requests against the protected APIs could look like as follows:
https://<your-funapp-name>.azurewebsites.net/api/<httpTrigger-functionName>
Header: x-zumo-auth:<AuthenticationToken>
NOTE:
For this approach, the related HttpTrigger functions need to allow anonymous accessing and the App Service Authentication also needs to choose Allow Anonymous requests (no action). Otherwise, the App Service Authentication and function level authentication would both validate the request. For the protected APIs, op needs to manually add the System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated checking.
Try this: https://liftcodeplay.com/2017/11/25/validating-auth0-jwt-tokens-in-azure-functions-aka-how-to-use-auth0-with-azure-functions/
I successfully made it work using this guide. It took awhile due to nuget versions.
Follow that guide properly and use the following nuget versions
IdentityModel.Protocols (2.1.4)
IdentityModel.Protocols.OpenIdConenct (2.1.4)
IdentityModel.Tokens.Jwt (5.1.4)
Oh and, the guide tells you to write your AUDIENCE as your api link, don't. You'll get unauthorized error. Just write the name of your api, e.g. myapi
If you get error about System.http.formatting not being loaded when running the function, try to reinstall NET.Sdk.Functions and ignore the warning about AspNet.WebApi.Client being restored using .NETFramework. And restart visual studio.
What you're describing is something that you should be able to do yourself by doing a little bit of research. To address your specific questions:
Create a JWT Token - ???? No documentation available!
The link Bruce gave you gives a nice example for how to create a JWT: https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
There's no documentation because you're basically inventing your own protocol. That means how you do it is entirely up to you and your application requirements. If it's a login action, it might make sense to return it as part of the HTTP response payload. Just make sure that you're using HTTPS so that the token stays protected over the wire.
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
How you send the token is, again, entirely up to you. Most platforms use the HTTP Authorization request header, but you don't have to if you don't want to.
The JWT token is validated - ???? No documentation available!
Use the ValidateToken method of the JwtSecurityTokenHandler (see the previous link for how to get the JwtSecurityTokenHandler). Docs here: https://msdn.microsoft.com/en-us/library/dn451155(v=vs.114).aspx.
I created an Azure Functions input binding for JWT Token Validation. You can use this as an extra parameter with the [JwtBinding] attribute. See https://hexmaster.nl/posts/az-func-jwt-validator-binding/ for source and NuGet package information.
Basically Azure Functions built on top of ASP.NET Core. By making some dependency injection tricks you could add your own authentication and policy-based authorization. I created demo solution with JWT authentication just for fun, beware to use it on production.

GCP Consume a REST API after OAuth in Node.js

I am working to implement a Node.js webapp to be deployed on GCP App Engine.
Following the Node.js Bookshelf App sample, I did manage to implement a basic user authentication flow using the passport-google-oauth20 and retrieve basic profile information. I basically just got rid of what was not needed for my purposes
My custom code is available at: gist.github.com/vdenotaris/3a6dcd713e4c3ee3a973aa00cf0a45b0.
However, I would now like to consume a GCP Cloud Storage API to retrieve all the storage objects within a given buckets with the logged identity.
This should be possible by:
adding a proper scope for the request.
authenticating the REST requests using the user session token obtained via OAuth.
About the post-auth handler, the documentation says:
After you obtain credentials, you can store information about the
user. Passport.js automatically serializes the user to the session.
After the user’s information is in the session, you can make a couple
of middleware functions to make it easier to work with authentication.
// Middleware that requires the user to be logged in. If the user is not logged
// in, it will redirect the user to authorize the application and then return
// them to the original URL they requested.
function authRequired (req, res, next) {
if (!req.user) {
req.session.oauth2return = req.originalUrl;
return res.redirect('/auth/login');
}
next();
}
// Middleware that exposes the user's profile as well as login/logout URLs to
// any templates. These are available as `profile`, `login`, and `logout`.
function addTemplateVariables (req, res, next) {
res.locals.profile = req.user;
res.locals.login = `/auth/login?return=${encodeURIComponent(req.originalUrl)}`;
res.locals.logout = `/auth/logout?return=${encodeURIComponent(req.originalUrl)}`;
next();
}
But I do not see where the token is stored, how can I retrieve it and how to use it to consume a web-service (in my case, GCP storage).
I am not at all a node.js expert, so it would be nice having a bit more clarity on that: could someone explain me how to proceed in consuming a REST API using the logged user credentials (thus IAM/ACL privileges)?
If you want to access Cloud Storage through the use of a token obtained with OAuth, when the application requires user data, it will prompt a consent screen, asking for the user to authorize the app to get some of their data. If the user approves, an access token is generated, which can be attached to the user's request. This is better explained here.
If you plan to run your application in Google App Engine, there will be a service account prepared with the necessary authentication information, so no further setup is required. You may need to generate the service account credentials (generally in JSON format), that have to be added to the GOOGLE_APPLICATION_CREDENTIALS environment variable in gcloud.
Here is an example of how to authenticate and consume a REST API with the token that was obtained in the previous step. This, for example, would be a request to list objects stored in a bucket:
GET /storage/v1/b/example-bucket/o HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer [YOUR_TOKEN]

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