How do I redirect a failed login attempt in node-oidc-provider - node.js

I'm setting up an OpenID Connect Provider using node.js, express.js, and node-oidc-provider. I've been working my way through the examples at https://github.com/panva/node-oidc-provider-example/tree/master/03-oidc-views-accounts, but it never deals with a failed authentication. How do I redirect the user back to the login page if they mis-type their password?
expressApp.get('/interaction/:grant', async (req, res) => {
// The initial route hit by the client (Relying Party) that renders the login view if needed.
...
});
expressApp.post('/interaction/:grant/login', parse, (req, res, next) => {
User.authenticate(req.body.email, req.body.password)
.then((users) => {
// returns an array of user objects that match the credentials
if(!users.length)
{
// What now? I can't just redirect back to /interaction/:grant - I get session not found
}
// the rest works well enough (for now)....
...
}).catch(next);
});

Just like in any express app. Think of it this way. Only resolve the interactions with success, or error if you wish to exit the interactions and return control back to the client.
I tend to develop interactions separately and only plug them to oidc-provider when they’re done.

Related

Passport-auth0 - infinite redirect loop, "Invalid authorization request state."

I'm trying to get a basic Auth0 app running. I followed the Node example on the Auth0 dashboard but I ran into an infinite redirect loop between /login and /callback. I tried to simplify the code using the getting started example of this repo's readme, right now my routing code looks like this:
app.get('/login',
passport.authenticate('auth0', {scope: 'openid email profile'}),
(req, res) => res.redirect("/")
)
app.get("/callback",
passport.authenticate('auth0', {failureRedirect: '/login'}),
(req, res) => {
if(!req.user) throw new Error("user null")
res.redirect("/")
}
)
Everything about my setup follows the instructions I got on my Auth0 dashboard.
I did some digging and found out that /login is called twice, then /callback is called twice, then /login twice and so on and so on. I also found out that if I give the /callback's passport.authenticate a callback, it receives these arguments: null, false, {message: "Invalid authorization request state."}
Google didn't find anything meaningful when I searched for the phrase "Invalid authorization request state." and I did everything according to the docs. Any idea what I'm doing wrong?
I have had the same issue with these error and was caused due to session loss on Kubernetes landing my calls to different instances each time (sort of like load balancing), what we did was to lower from 3 instances to 1 and that fixed it. Also you could set in your Auth0Strategy config the value of state: false to double check if this lets you move on.
It turns out I didn't have the /callback route set up properly. This is the proper setup:
router.get("/callback", (req, res, next) => {
passport.authenticate('auth0', (err, user, info) => {
if(err) return next(err)
if(!user) return res.redirect("/failure?info=" + JSON.stringify(info))
req.logIn(user, err => {
if(err) return next(err)
const returnTo = req.session.returnTo
delete req.session.returnTo
res.redirect(returnTo || '/secret')
})
})(req, res, next)
})
res.redirect should lead somewhere else and req.logIn needs to be called with the proper arguments
For those who are still having issues, the problem might lie elsewhere. When I ran into this it turned out to be caused by session cookies that weren't persisting! It turned out my reverse proxy (running on Apache) wasn't configured properly. I've described my solution here: https://stackoverflow.com/a/67891167/8221175
As for why this might happen for those interested, I've posted an explanation on one of the GitHub issues here: https://github.com/auth0/passport-auth0/issues/89#issuecomment-856971807
In short: The state query parameter in the response of a login call is saved in the session. If sessions don't persist, passport can't get that state data and it'll think someone is hijacking your session. That causes the “Invalid authorization request state.” message, as well as the user to be falsy in the passport.authenticate callback. If your code then redirects to '/login', the whole thing repeats, causing an infinite loop.
The fix is to make sure your cookies are saved properly and your sessions therefore persist. You can use the examples I've provided in the links.

add custom query param to passport auth0 strategy authenticate request

I'm using passport.js and auth0 strategy to auth users
I'm also using auth0's hosted login page, which supports query parameters like customQueryParam here
ex: https://cool-startup.auth0.com/login?client=some_client_ID&...bunch of params...&customQueryParam=true
You can use customQueryParam to control the auth0 hosted login page and show flash messages and stuff, its handy
here's my issue
after my auth0 middleware runs and I've determined I need to redirect the user back to my auth0 login page with a custom parameter, how should I accomplish that in the context of using passport.js / is it possible?
I'm looking at the source code here
https://github.com/auth0/passport-auth0/blob/master/lib/index.js
which inherits from https://github.com/jaredhanson/passport-oauth2/blob/9ddff909a992c3428781b7b2957ce1a97a924367/lib/strategy.js
and I'm a bit stumped
here is where I find out that I have an error and I need to redirect the user back to auth0 with a custom parameter in the url
app.get('/auth/callback', (req, res, next) => {
passport.authenticate('auth0',
{},
(err, user) => {
if (err) {
// run passport.authenticate('auth0',
// again, but add custom query param
}
return res.redirect('/');
})(req, res, next);
});
any help is greatly appreciated / thanks for reading
You can build the /authorize URL yourself as done here and redirect manually: https://github.com/auth0-samples/auth0-regular-webapp-login-with-sso-and-api/blob/master/utils/authorize.js
Since the URL is in your control here, you can add any query parameters as you'd like (although sending non-standard query parameters to the login page is something that's generally discouraged).

Authenticate before calling route controller

I'm working on an API using restify. There will be a dozen or more endpoints and each one requires authentication. The API will be stateless, so each API request, regardless of endpoint, will pass credentials.
What I'd like to do, if possible, is to authenticate before negotiating the route. Otherwise, if I have a route:
server.get('/activities', activities.index);
Then, within activities.index (and every other routing method), I have to duplicate the following:
var user = require('../models/user')(server);
user.authenticate(req.authorization, function(err, user) {
...
// Do the real activities-related stuff.
});
This is one of those things where it feels like there must be a better way of doing it, but I don't know what it is.
Anyone have any thoughts?
So you can register handlers to be ran before every route is ran.
http://mcavage.me/node-restify/#Common-handlers:-server.use()
server.use(function(req, res, next){
//do authentication here
if(authenticated){
return next();
}
else{
res.send({auth:false});
})
So when you use server.use when the user asks for /activites it will run all of the server.use you created in the order you created them before running the code for the route.

How can I specify what PassportJS does after a callback without using ExpressJS?

The PassportJS website has the following code example, where somebody can specify their own flow of logic after a callback goes through:
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/');
});
However, I am not using Express, and am finding it very difficult to replicate the above behavior.
Here is my current code that deals with facebook authentication callbacks:
if(path == '/auth/facebook/callback'){
passport.authenticate('facebook', {failureRedirect: '/failbook', 'successRedirect':'/success'})(req, res, next);
return;
}
I have no idea how to change it so that I can alter the flow of logic post-callback. I'd like to be able to check some variables that I have saved and redirect to different locations accordingly. Any thoughts on how I can go about doing this?
Also - on a related note - if I'm just refreshing the facebook access token (AKA if it has expired and I'm getting a new one), is it possible to not redirect the user anywhere at all, so that their browser doesn't go to a different page at any point in time during the refreshing process (which involves a re-authentication with facebook)?
check this https://groups.google.com/forum/#!topic/passportjs/HTG13e2pb74
its a group which uses passport with node "vanilla"

redirect before loading URL

I'm developing a node.js app where I'm using passport to build OAuth authentication system. I can access the user through request object in each resource load after configurating it. But my question is: How can I do to check before every URL load - resources defined with app.get('/', function(..) {...}) - if user is loged and redirect the client if it's not loged. I could do it just adding a test in every method, but this is not what I want.
Thanks!
You want a middleware that checks whether the user is logged in.
isAuthenticated = function (req, res, next) {
if (req.user)
return next(); // All good, let the route handler process the request.
else
res.redirect('/login'); // Not logged in.
}
And to use it on every route that needs to be logged in:
app.get('/something', isAuthenticated, function (req, res) {
// Only in here if the user is authenticated.
});
You can also use the middleware on every route, by doing app.use(isAuthenticated), but you will need to have extra logic in the method to not create infinite redirect loops to /login, etc.

Resources