How to use keycloak with NestJS properly - node.js

I need to use keycloak with NestJS and GrapphQL (type-graphql). There are some guides for using it with pure Express, but I'd prefer using with NestJS auth pattern. Can someboby give any suggestion?

This is a kind of an old question, but since I just went through implementing it, I would like to point to a great tutorial Protecting your NestJS API with Keycloak. It does not use passport, but is simply call the OpenId Connect UserInfo endpoint on Keycloak: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo.
I find it very easy to add to an application, very easy to follow, and generally very well usable (comparing to an unnamed SaaS application I was using before).
async authenticate(accessToken: string): Promise<User> {
const url = `${this.baseURL}/realms/${this.realm}/protocol/openid-connect/userinfo`;
try {
const response = await this.httpService.get<KeycloakUserInfoResponse>(url, {
headers: {
authorization: `Bearer ${accessToken}`,
},
}).toPromise();
return {
id: response.data.sub,
username: response.data.preferred_username,
};
} catch (e) {
throw new AuthenticationError(e.message);
}
}

I never tried it myself, but i guess i will soon. What i would do:
Check out the Authentication Technique again, and especially learn how to implement the different strategies of passport in nest: https://docs.nestjs.com/techniques/authentication
Take a look at the npm-package and it's documentation. The guys from passport have dedicated a whole section to OpenID: http://www.passportjs.org/docs/openid/
Implement the OpenID-Strategy in nestjs - here i would just follow the docs, since they are pretty good
I hope this will maybe help you out. At the end of the day, you will have an OpenID implementation of passport with KeyCloak and can use a guard to protect your Routes / Schemes.

Related

NestJS Fastify Authentication

So I replaced ExpressJS with Fastify, but my problem is Nest-Passport doesn't support fastify, do we have an alternative for Nest-Passport? or any solutions on how to secure RestAPI in nestJS using a token?
I dont kown if this is the correct manner. But if I change the default jwt extractor
ExtractJwt.fromAuthHeaderAsBearerToken
(described within the doc ) by a custom one it works.
const fromFastifyAuthHeaderAsBearerToken = (request: FastifyRequest): string => {
const auth = request.headers['authorization'];
const token = auth?.split(' ')[1];
return token;
}
There's no immediate Fastify NestJJS authentication package I'm aware of (I'm sure there's something out there), but I do have a sample of JWT authentication with Fastify and NestJS without Passport. The idea is to make use of Nest's #nestjs/jwt package or just jsonwebtoken directly, and create the auth tokens with that instead of delegating to Passport. This is actually the kind of approach I prefer, as I find Passport to be a bit too mystical sometimes.

Microservices API Authentication with API Gateway in NodeJS/Express

I'm creating a Microservice architecture using Node JS and Express. I know that one of the main features of Microservices are a service oriented architecture where teams can design, develop and ship their applications independently. So in my design I think that each microservice offers their APIs and they communicate between each other with the API in this way each Microservice is independent and have it's own life waiting for request.
I am writing this question because I have several doubts about
authentication and communication between microservices.
For the autentication I have made some test with JWT to authenticate the API of a Microservice and all works fine, this is an example of express middleware for authentication:
const tokenCheck = (req, res, next) => {
let token = getToken(req);
if (token) {
jwt.verify(token, "password, (err, decoded) => {
if (err) {
throw "Failed to authenticate token.";
} else {
req.user = decoded;
next();
}
});
} else {
throw "No token provided.";
}
};
Used in this way:
router.get("/", tokenCheck, Controller.get);
So each route is protected with a layer of autentication.
Instead about communication between microservices I read the best way is to use an API Gateway and I found this library to do it, furthermore i read that it's better to add the authentication middleware inside the API Gateway because if you re-implement these things in each single microservice, you are duplicating the code at first, but more importantly you have two different pieces of software to maintain.
Now my question are two:
1) Is right use an API gateway like this to make communication between microservices?
2) If I move the authentication middleware from the microservices to the API Gateway I have to remove the middleware from the API routes and in this way the API will be unprotected if someone other than the gateway make requests and I think this is wrong because anyone can call that routes, instead if I mantain the middleware also is the mircorservice the code is duplicated, can anyone tell me what is the right way to do it?
I have been working on Node.js from past couple of years and here is my understanding, hope this helps you clear your thoughts.
The answer to your question:
Let me explain to you the work of both the parts you have stated in the question.
http-proxy-middleware
Proxy: In simple words, the proxy means duplicate clone to turn your traffic too.
Read more: What is the proxy server?
Your custome middleware
Your custom middleware is the project specific code to check if all the requests are authenticated.
It would check if the request has a token and if the token is valid.
Conclusion:
You need your custom middleware compulsorily. Another one (http-proxy-middleware
) is optional.
Update:
Now my question are two:
Is right use an API gateway like this to make communication between
microservices?
Answer: No, it is not the right way.
If I move the authentication middleware from the microservices to
the API Gateway I have to remove the middleware from the API routes
and in this way the API will be unprotected if someone other than the
gateway make requests and I think this is wrong because anyone can
call that routes, instead if I mantain the middleware also is the
mircorservice the code is duplicated, can anyone tell me what is the
right way to do it?
For this, you can impose the authentication middleware on app so that all the routes execute the middleware.
Update your server code.
// Init App
const App = Express();
// Authentication code
App.use((req, res, next) => {
let token = getToken(req);
if (token) {
jwt.verify(token, password, (err, decoded) => {
if (err) {
throw "Failed to authenticate token.";
} else {
req.user = decoded;
next();
}
});
} else {
throw "No token provided.";
}
});

What's the better way of implementing security with MEAN.js

I'm working with mean.js, and I have a little doubt about authentication and authorization here...
MEAN.js come with a out of the box passport.js implementation that seems to be working good enough for me just to know when a user is logged in. But at the moment of authorization some question pop up in my mind.. doing my research I reach some answers and I don’t know what is the best way of implementing security API calls in my app.
So far, I'm taking this solution:
Using express.all() function to set in one file all my authorization functions ( I guess it is a good practice right ? ).. creating a file with the following code example:
'use strict';
var passport = require('passport');
module.exports = function(app) {
app.route('/private/p/*').all(function(req, res, next){
if(!req.isAuthenticated()){
res.send(401);
}else{
next();
}
});
app.route('/private/byRoles/*').all(function(req, res, next){
if(!req.isAuthenticated()){
res.send(401);
}else{
var urlRoles = ['admin', 'godlike'];
// ROLE LOGICS THAT ARE GOING TO BE ADDED TO MY USER
// GETTING MY USER ID BY THE DE-SERIALIZE PASSPORT FUNCTION AND GETTING MY
// MONGO MODEL FOR MY USER, WITH THE INFO OF ROLES IN THERE AND DOING
// SOME LOGICS HERE ABOUT THE ROLES AND URL PATTERN.
if ( hasRole(urlRoles, user.roles)){
next();
}else{
res.send(401);
}
}
});
};
So far this is the solution that I'm planning to implement, but I would like to be sure of what I'm doing here... is there a better way of implementing authorization in mean.js ? Is this authorization middle-ware wrong implemented with passport? I don't sure if is necessary to implement another strategy to this.. or if this implementation has a security lack ( sure it has to ).. is better to use Oauth or using api token ??? what should be the architecture to secure an app made in MEAN.js supporting roles and permissions ?? also in the future I would need to secure my socket.. I was looking at passport-socketio.. but not sure if is there a better solution.
I use JWT's for my angular apps. There are many articles out there about the benefits for using tokens instead of sessions or cookies Cookies vs Tokens. Getting auth right with Angular.JS.
You can do everything you want with JWT, roles for backend and frontend, securing sockets is also possible and there are packages for this functionality. You do not need passport if you using tokens. You check the the credentials one time and store the token in the browsers local storage. There are many packages for express and JWT Express-JWT
For a closer look at JWT jwt.io

Passport.js: passport-facebook-token strategy, login through JS SDK and THEN authenticate passport?

I was looking for a way to let my client authorize with the facebook JS SDK and then somehow transfer this authorization to my node server (so it can verify requests with the fb graph api)
I stumbled across:
https://github.com/jaredhanson/passport-facebook/issues/26
&
https://github.com/drudge/passport-facebook-token
what seems to be an entirely different strategy from passport-facebook.
Am I correct when assuming that:
One logs in with the fb JS SDK, and then the facebook-token strategy somehow extracts the token and fb id from the document or body object?
Or is there any other decent way to achieve this? I'm namely trying to avoid the redirects enforced by the server SDKs
I've spent a couple of days this week trying to figure out the best way to use Facebook Authentication for a private API, using passport.js — passport-facebook-token is perfect for this.
You are correct in assuming these are two separate authentication strategies. You don't need passport-facebook installed to use passport-facebook-token.
If you have Facebook authentication implemented in the client-side JS (or iOS etc.), and are looking for a way to then authenticate API requests using your user's Facebook authToken, passport-facebook-token is a really elegant solution.
passport-facebook-token works totally independently of passport-facebook, and basically handles the redirects required by Facebook internally, before passing the request along to your controller.
So to authenticate an API route using passport-facebook-token, you'll need to set up a passport strategy like so:
passport.use('facebook-token', new FacebookTokenStrategy({
clientID : "123-your-app-id",
clientSecret : "ssshhhhhhhhh"
},
function(accessToken, refreshToken, profile, done) {
// console.log(profile);
var user = {
'email': profile.emails[0].value,
'name' : profile.name.givenName + ' ' + profile.name.familyName,
'id' : profile.id,
'token': accessToken
}
// You can perform any necessary actions with your user at this point,
// e.g. internal verification against a users table,
// creating new user entries, etc.
return done(null, user); // the user object we just made gets passed to the route's controller as `req.user`
}
));
It's worth noting that the User.findOrCreate method used in the passport-facebook-token Readme is not a default mongo/mongoose method, but a plugin that you'll have to install if you want it.
To use this auth strategy as middleware for any of your routes you'll need to pass it an access_token object either as a URL parameter, or as a property of the request body.
app.get('/my/api/:access_token/endpoint',
passport.authenticate(['facebook-token','other-strategies']),
function (req, res) {
if (req.user){
//you're authenticated! return sensitive secret information here.
res.send(200, {'secrets':['array','of','top','secret','information']});
} else {
// not authenticated. go away.
res.send(401)
}
}
NB. the access_token property is case-sensitive and uses an underscore.
The documentation for passport-facebook-token isn't extensive, but the source is really well commented and pretty easy to read, so I'd encourage you to take a look under the hood there. It certainly helped me wrap my head around some of the more general ways that passport works.

Node.js and Twitter API 1.1

I had a small web app that was using the Twitter API 1.0 user_timeline function to quickly get a user's recent tweets without authentication. However, now every call requires oAuth which I'm terrible at. I know there's an application only authentication method, which is what I want since this is an automated app and not a user based one.
The application was built in node.js so a suggestion for a module that supports app-based oAuth would be great. The main thing is I don't have nor need a callback page, which most assume, since all I'm trying to do is get the last few tweets from a handful of specific Twitter accounts which the app tracks. Likewise any links to good oAuth educational resources or, better yet, Twitter 1.1 HTTP request walkthroughs would be much appreciated.
Thank you for your time.
Twitter API 1.1 allows only authenticated requests. But the good news is that the oAuth based authentication is not that difficult. To use it:
Generate the four oAuth keys you need. Go to https://dev.twitter.com/apps/new and register your app.
Install package ntwitter on your machine.
Configure the four keys in your app. See the package page on how to do it.
Construct request and get results. See this page on how to make requests.
I find oAuth to be easier and prefer this way.
The package EveryAuth does authentication pretty well, too. Also, ntwitter isn't being updated very regularly right now; I found mtwitter to be much better. I suck at explaining stuff, so I'll just show you how I did it:
var mtwitter = require('mtwitter');
var twit = new mtwitter({
consumer_key: { your app consumer key },
consumer_secret: { your app consumer secret },
access_token_key: { get this from oauth or everyauth or whatever },
access_token_secret: { get this from oauth or everyauth or whatever }
});
twit.get('/statuses/user_timeline', { include_entities: true },
function (err, data) {
if (err) {
console.log(err.toString());
}
else console.log(JSON.stringify(data));
});

Resources