I have been learning Nest.js.
I integrated auth & authz with jwt + casl following the docs nestjs casl integration
github repo
Everything is working except casl conditional checking:
can(Action.Update, User, { id: user.id })
here, even though id isn't equal to user.id, it's not restricting the action
Related
We have a small React Web application with a Fastify backend (but can very easily apply the same concepts to Express js) that feeds the db data to the frontend clients.
Some of the API routes are protected by means of middleware checking the validity of the access token.
Our auth strategy used to be only credentials based, ie using Username and Password.
We have recently implemented authentication by Google and Facebook as well and for the most part, they seem to work well.
We now want to replicate our web application to a mobile application.
I have never written a mobile app and am currently busy learning React-Native.
I managed to implement Google Auth on the IOS app.
Here is the problem. I am not sure how to implement token validation for mobile clients on protected routes using the Google access token. I am however able to successfully implement validation if I use the id token.
My understanding is that validation on protected routes should be done using the access token, otherwise, what is the point of the access token in the first place.
Anyway, my understanding of the entire authentication flow is clearly flawed.
I just need some advice, samples or references to articles that I can read that can clarify the concepts to me.
Just the summary of what I hope to achieve:
a single backend with various (but not all) protected routes
the backend to support credential-based, Google and Facebook authentication strategies
backend middleware to check the validity of the access token
backend should serve both native mobile and web applications.
Sample of a protected route:
fastify.get(
"/protectedroute",
{ preValidation: [fastify.googleverify] }, //<--- Middleware only checking Google validity currently. TODO: Multi-provider middleware to be created
async (request, reply) => {
reply.code(200).send({ message: "authenticated", user: request.user });
}
);
Sample of middleware to check google id_token validity:
fastify.decorate("googleverify", async function (request, reply, done) {
if (!request.raw.headers.authorization) {
return done(new Error("Missing token header"));
}
const bearer = request.raw.headers.authorization;
const token = bearer.split(" ");
try {
const userinfo = await verify(token[1]);
request.user = userinfo;
return done();
} catch (error) {
reply.code(401).send({ message: "Not Authorized", error: error });
}
});
I'm trying to create a stripe connect account using my firebase functions backend when the user signs up but keep getting this error Express accounts may only be created via the OAuth flow I know the error seems self-explanatory that I need to use the standard OAuth registration method but in the Documentation it states that custom types can be created by the API and presenting the OAuth for every user who just wants to send funds and not receive is just annoying am I doing something wrong for the API not to create it? Or is there a workaround to not have to show the OAuth for users who just want to send funds?
exports.createStripeCustomer = functions.auth.user().onCreate(async (user) => {
const customer = await stripe.customers.create({email: user.email});
const account = await stripe.accounts.create({type: 'custom', business_type: 'individual', individual: {email: user.email}, requested_capabilities: ['card_payments', 'transfers'], email: user.email});
return admin.firestore().collection('stripe_customers').doc(user.uid).set({account_id: account.id, customer_id: customer.id});
});
Express Accounts and Custom Accounts are distinct types of accounts when using Connect. You can create Custom Accounts using the API, but Express Accounts must be created via OAuth.
The main difference is that Express Accounts have access to the Stripe Dashboard and can be updated in some ways by the end user, while Custom Accounts are entirely managed by the platform.
The issue seems to be being caused by me not specifying the Country in the stripe.accounts.create function. Once I did it created the account.
I am trying to create a nodejs api, that connects to to Azure Active directory using the ADAL plugin (https://github.com/AzureAD/azure-activedirectory-library-for-nodejs).
All works ok for normal users, but if a user has MFA (Multi-Factor Authentification) enabled, it fails and throws and error message.
I found this related to ADAL-MFA: https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/issues/151 but it's not clear for me from his answer if it's possible or not, and how to implement MFA.
The plugin has very poor documentation and it's not clear for me how I can retrieve the error message and vars from it. It's says that the error var is a object but it's a string.
Here is my code from the endpoint which works for normal users:
var adal = require('adal-node');
var AuthenticationContext = adal.AuthenticationContext;
var authorityUrl = parameters.authorityHostUrl + '/' + parameters.tenant;
var resource = '00000003-0000-0000-c000-000000000000';
var context = new AuthenticationContext(authorityUrl, true, new adal.MemoryCache);
context.acquireTokenWithUsernamePassword(resource, parameters.username, parameters.password, parameters.clientId, function(err, token) {
if(err){
mysql_connection.end();
return callback(null, {
status: false,
error: err.stack,
log: logging.message,
test: 1
});
}
)};
So basically I need to use user credentials (e-mail and password) to connect to AAD api, but server to server (my nodeJS api to AAD api). And it needs to work with MFA.
(web app -> nodeJS API -> AAD API)
acquireTokenWithUsernamePassword worked perfectly for this, but it does not work with MFA, or I don't know to make the correct adjustments to make it work.
You are using Resource Owner Password Credentials Grant flow (ROPC), and hit one of the exact scenarios why I tell people not to use it. (except maybe for test automation)
You can't use ROPC with users that have MFA. Neither can you use it with users who are federated from on-prem AD or Microsoft personal accounts. Or with users whose password has expired and needs to be reset.
You need to switch your API to acquire the token using either On-behalf-of grant flow (exchanges the access token your API got for a new token, continuing the delegation) or client credentials flow (acquire token with app credentials alone, no user context).
On-behalf-of flow
I'm able to register and authenticate users via amazon-cognito-identity-js
and aws-sdk and the process to implement it was pretty much straightforward and simple. Now I have few APIs built in node.js, how would I authorize these APIs using Cognito policies (i.e permissions) and wrap them around logged in user where I'm already able to get idToken, accessToken and refreshToken.
Other things I came across while reading the documentation and watching video tutorials are aws-lambda and aws-api-gateway. I understood that aws-lambda is a way to define methods that can communicate with no-sql database (i.e AWS dynamo) and api-gateways to access those lambda functions and interact with DB and that all is serverless.
My question is, what if I have my own APIs written in Node.js and I need to integrate Cognito user pools with it and to protect those resources using AWS Cognito policies, user groups and roles, is it possible? Please guide me in this regard.
You can use the same authentication token which you get when you authorize the user to authorize your node.js APIs too. It can be done in many ways. One of the ways can be calling a isAuthenticated() method in each constructor which will check if there is a valid token or not.
export interface LoggedInCallBack{
isLoggedIn(message:string, loggedIn:boolean):void;
}
isAuthenticated(callBack : LoggedInCallBack){
if(callBack==null){
throw("User login service call cannot be null");
}
console.log("Is authneticated");
var cognitoUser = this.cognitoUtil.getCurrentUser();
console.log("Is cognito user empty? " + cognitoUser);
if(cognitoUser!=null){
cognitoUser.getSession(function (err, session){
if(err){
console.log("Couldn't get session:" + err);
callBack.isLoggedIn(err, false);
}
else{
console.log("Session is: " +session);
callBack.isLoggedIn(err, true);
}
})
}
else{
callBack.isLoggedIn("Cannot retrieve the current user", false);
}
}
Recently I was working on a nodeJS project and I was thinking how to go about and implement the security module of my mobile application. I had a previous experience from OAuth 2.0 protocol which I used in C# projects in the past.
In .NET there are two nice open source project
https://github.com/thinktecture/Thinktecture.IdentityServer.v3
https://github.com/thinktecture/Thinktecture.AuthorizationServer
The former is an Identity Provider supporting federated authentication and the later is an OAuth 2.0 provider.
So I decided to employ the same security infrastructure for my nodeJS app. But as far as I know, there is nothing equivalent to those projects.
I found some really nice project, which are not yet complete but are a good start:
https://www.npmjs.org/package/node-oauth2-server
https://github.com/domenic/restify-oauth2
In addition, I came across a nice article that suggests a nice way to deal with authentication in nodeJS. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/ and a similar answer to a questtion on stackoverflow. Auth between a website and self-owned API
From what I understood, expressJwt guards our api's and basically will validate the access token sent by the user. But I'd like to go a step further, and associate a token with app specific scopes, in a similar way that one would do with the OAuth2.0 protocol. So for example, I would like to assign a write, read etc. scopes and have expressJwt check if the user's token has the required scopes to access as specific API endpoint.
I would be grateful if you could provide me with some suggestions about how to deal with this topic.
First, you need to generate a token with such claims. This could be in an API or some other place:
var jwt = require('jsonwebtoken');
var claims = {
name: user.name
can_write: true,
can_post_timeline: false
};
var token = jwt.sign(claims, 'my-super-secret');
Then, to validate you will do something like this:
var jwt = require('express-jwt');
app.use(jwt({secret: 'my-super-secret'}));
function require_time_line_access (req, res, next) {
if (!req.user.can_post_timeline) return res.send(401);
next();
}
app.post('/timeline',
require_time_line_access,
function(req, res) {
//do timeline stuff
});
express-jwt validates the signature of the token, expiration and few other things. If everything is okay it puts the decoded token in req.user, and if is not okay it returns 401.
require_time_line_access is a middleware that ensure the user has this claim, if it doesnt it returns 401. You can put this middleware in every endpoint that needs this claim.