Azure AD callback URL is not getting hit every time - node.js

It gets hit only when I clear site data and then try to login with Azure AD. Tried setting cache to no-store for all the requests but still not working.

You need add prompt: 'login', like below in your nodejs project.
passport.authenticate('azuread-openidconnect',
{
response: res,
prompt: 'login',
failureRedirect: '/',
failureFlash: true,
successRedirect: '/'
}
)(req,res,next);
The specific implementation method is modified according to your project. Adding prompt=login in the redirect url can force a password to log in every time. It is no longer necessary to clean up the browser cache and log in with a username and password.
Related Posts:
1. Unable to login more than one account of the same domain when using Azure AD as the IdP for G Suite
2. Providing user parameters in azure active directory authentication

Related

Keycloak and nodeJS : Unable to refresh with expired refresh token

EDIT : I've set a server on a vm, without Docker, and everything worked well, it looks like VM+Docker is too much layer.
I have a node backend, with a route protected with :
app.get('/api/user', keycloak.protect(), function(req, res) {
res.json({ message: 'This is an USER endpoint payload' });
});
I have this keycloak.json :
{
"realm": "MyRealm",
"auth-server-url": "http://keycloak.com:8008/auth/",
"ssl-required": "none",
"resource": "sso_agt",
"public-client": true,
"confidential-port": 0
}
When I use this route, i'm redirected to the auth page. When i'm logged, it redirects me to the right url, but I have denied access, with this error in npm console :
Could not obtain grant code: Error: Unable to refresh with expired refresh token
In my keycloak console, i have a WARN type=CODE_TO_TOKEN_ERROR
I run keycloak with docker, on a Ubuntu Server VM.
Refresh tokens are no-expiration passwords, when combined with the clientId and client service allow for the generation of actual access tokens. Once a refresh token is marked as invalid, there is no way to get a new one without navigating the user through implicit login flow with the scope: offline set.
I've set a server on a vm, without Docker, and everything worked well, it looks like VM+Docker is too much layer.

when does the passport.js failure redirect gets hit?

I have been using passport.js to perform OAuth. So the redirect URI gets hit after successful authentication,
However for the failure scenarios. I am not able to trigger it anyway,
What happens in the following scenarios?
1. When the google/twitter or any OAuth provider opens their sign-in page but the user doesn't respond at all / closes the browser window /, how do I hit the failure URL/redirect URL after a timeout.
2. There isn't any cancel button to abort the Google OAuth sign-in, I expect at least then failure gets called.
Basically, all I wanted to know is, all possible use cases/scenarios do the failure URL gets called?
Sample code for Google OAuth redirect, I believe the failure scenarios are same for all the OAuth providers.
app.get('/oauth/failure', function (req, res, next){
console.log('Query params:', req.params.provider);
console.log('failure login called');
res.send("<script> window.close()</script>");
});
app.get('/oauth/redirect/google', passport.authenticate('google', { failureRedirect: '/oauth/failure?provider=google' }), (req, res) => {
if(req.user.id){
// gets executed for successful authentication
let redirectUrl = `http://localhost:8082/auth.html?pid=${req.user.id}`
res.redirect(redirectUrl)
}
});
The above is just an example from passport-google-oauth, I beleive same is the case for any passport strategy.
If authentication fails ( the user enters wrong email or password ), the user will be redirected back to the page of your choice for another attempt.
When a user grants OAuth access, He himself hits the redirect uri and as far as I know there is no way to know if the user rejected access. If you would like to implement a failure Redirect URI you can add a window.onbeforeunload event listener and hit your failure endpoint whenever a user is about to exit your page.

Passing OAuth user data back to React via Node (Passport) authentication

I'm a little confused about the flow of data in a React application that authorizes a user through a third party OAuth provider. Right now I have a login button in React that directs to a Node server.
Log In
This directs to an Express route...
router.get('/auth/google',
passport.authenticate('google', {
session: false,
scope: ['email']
}));
that uses Passport to verify the login request.
passport.use(new GoogleStrategy({
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_SECRET,
callbackURL: "http://localhost:5000/api/auth/google/callback"
},
function (accessToken, refreshToken, profile, cb) {
return cb(null, profile);
}
));
The callback is set up to redirect the user back to the React application.
router.get('/auth/google/callback',
passport.authenticate('google', {
session: false,
failureRedirect: 'http://localhost:3000'
}),
function (req, res) {
// Successful authentication, redirect home.
res.redirect('http://localhost:3000');
});
This method allows me to either add a user to my DB via my Node app, or confirm the existence of the user already in my DB, and that's as far as I've seen any tutorial take it, but it seems entirely useless without the ability to send this information back to React. The point of logging in, at least in my opinion, is to have my application function specific to a user.
What I'd like to be able to do is send back a signed JWT token. Either one signed manually with my server, or the access token that passport gets from Google, either will do. As well, I'd like to send a user ID. I need this so my app can make API calls with the user ID as part of the request to protected routes, thus the need for the JWT.
It's confusing to me because without this exchange of data, the purpose of OAuth seems essentially useless, so I must be missing a vital step in the process, or I must be looking at the problem from the wrong perspective. Where or how should I be informing my React application of the details of the logged in user, and give them a token for local storage? As far as I can tell, there's no way to send package of data back with the callback URL.
I found a way, you can use eventsource for this. Check this article for more information https://www.blog.tericcabrel.com/implement-server-sent-event-in-node-js/
You can send you token as query param in your frontend app
res.redirect(`http://YOUR_FRONTEND_HOST:3000/?token=` + "Your jwt token")
So in the frontend you can retrieve the token with a useEffect then make it disappear to don't make it avalible to the user.

Node.js SAML implementation with OneLogin

I am looking to setup our application in the application catalog of OneLogin, thus I need to create a SAML integration, as I understand it. I do see that they have toolkits available for this, but I am working in Node.js and there is no toolkit for that environment.
I have been reading their documentation as well as other posts and think that the process is something like the following:
1) Make a request to OneLogin to create the application and add it to their catalog.
2) My application needs to have a route point that I will provide to OneLogin which will be used as the redirect when someone clicks the icon for our app.
3) A user clicking on the icon for my app in the catalog will tokenize the user and send that to my defined route point with the information passed as a SAML request / XML.
4) My route point will need to consume the SAML request / XML and then will perform my internal login process. The information passed to my route point by OneLogin will include the necessary information for my site, like first name, last name, and email address. I will then do my internal application with that information and if it validates to an existing user, I would count that as a successful login and then let them continue. If they are not an existing user, I would send them through a user creation type form, but could default information from the SAML request / XML from OneLogin, or could just automatically create the user.
Does that seem like I have a high level understanding of the process?
Does anyone have examples in Node.js?
I was going to use the passport-SAML package.
Yes you're on the right track.
Passport-SAML works well for Express apps https://github.com/bergie/passport-saml
Your Passport SAML Strategy configuration should look something like this.
passport.use(new SamlStrategy(
{
path: '/login/callback',
entryPoint: 'https://{SUBDOMAIN}.onelogin.com/trust/saml2/http-redirect/sso/{APP_ID}',
issuer: 'passport-saml'
},
function(profile, done) {
console.log(profile);
return done(null, profile);
})
);
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
Be sure to use the SLO Endpoint that is provided when configuring your app via the OneLogin portal.
Then setup your routes to use Passport
// Initiates an authentication request with OneLogin
// The user will be redirect to OneLogin and once authenticated
// they will be returned to the callback handler below
app.get('/login', passport.authenticate('saml', {
successReturnToOrRedirect: "/"
}));
// Callback handler that OneLogin will redirect back to
// after successfully authenticating the user
app.post('/login/callback', passport.authenticate('saml', {
callback: true,
successReturnToOrRedirect: '/users',
failureRedirect: '/'
}))
You also need to make sure you have set the ACS (Consumer) URL to your apps callback url and that the user you are testing with has access to the app.

Loging out of Azure Passport authentication Node js

I have a node js application in which we have used azure login with passport authentication.
I have successfully logged in using azure and the application is working fine.
But, when I logged out and give the url to a page - it checks for authentication and automatically go to that page without asking for login.
Once I logged in my url contains below query string
1. session_state
2. code
3. state
4. token
Log in Code:
app.get('/login', passport.authenticate('azuread-openidconnect', { failureRedirect: '/' }), function (req, res) {
res.sendFile(path.join(__dirname+'/index.html'));
});
Logout code:
app.get('/logout', function (req, res) {
req.session.destroy();
req.logout();
res.redirect('/');
});
When i logout the page redirects to my index page. Then when i give '/login' to the url it takes me to the page without going to logging in page
Please help to get out of this...
This issue is caused by the Authorization Code Grant Flow of OAuth 2.0. Something like that there are any session on Azure AD OAuth 2.0 service. It is not the problem of passportjs or expressjs.
We can have the following simple test, visit the authentication endpoint in browser, https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token%20code&client_id=<client_id>&redirect_uri=<redirect_uri>&response_mode=query&scope=openid
You will need to fill the email and password first, after you finishing the login flow, the second time you visit the endpoint, you will not longer need to fill the email or password anymore.
We can set the url param prompt to login in the authorize endpoint to force the users to re-authenticate every time.
You can refer https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx#code-snippet-3 for the details.
But in the azure passport oidcstrategy, we should modify the source code for add the param into the endpoint.
After you install the passport-azure-ad module, open the file /node_modules/passport-azure-ad/lib/passport-azure-ad/oidcstrategy.js, at Line 545 (more or less), you can find the following code snippet:
var params = {};
if (self.authorizationParams) { params = self.authorizationParams(options); }
params['response_type'] = config.responseType;
log.info('We are sending the response_type: ', params['response_type']);
params['client_id'] = config.clientID;
params['redirect_uri'] = callbackURL;
...
We can add the sentence params['prompt'] = 'login'; following the code snippet to add the support.
Any further concern, please feel free to let me know.
edit
Is there any way to prompt login only when i logged out...
I am not sure that do you mean, you want to check the user is authenticated when he visit login route, if is, do not prompt login flow?
If so, you can custom a middleware to check the authenticated. E.G.:
function checkAuthenticatedOnLogin(req,res,next){
if (!req.isAuthenticated()) {
return next();
}else{
res.send('do not need login');
}
}
app.get('/login',checkAuthenticatedOnLogin,
passport.authenticate('azuread-openidconnect',{ failureRedirect: '/login' }),
function(req, res) {
log.info('Login was called in the Sample');
res.redirect('/');
});
Logging out of your application does not mean the user is logged out of Azure. When a user logs out of your application you simply destroy the session your application has for said user. When they go to login again it will redirect them to Azure (where they're still logged, and where your application still has permission) which then instantly redirects back to your application with a token for that user. You would need to have the user log out of Azure to have them prompted again for their credentials.
1) I had this same problem, as passpor-azure documented I was executing this function to logout:
logout: function(req, res) {
req.logout();
res.redirect('/');
}
But Azure login session keeps active, so when I re-enter into my website, the autentication request will automatically be valid and no login page will be showned.
I tried #Gary Liu - MSFT suggestion to configure prompt:login option, but has #user3211705 commented, this makes login page reappear (even if I don't do logout and I have a portal.azure.com tab open), for instance when I restart my server (note: this isn't wrong, but when we are developing, one restarts the server all the time, and it gets annoying to login all the time)
2) Part of my solution came from this post:
Which suggest to invoke this url to logout user at Azure AD:
https://login.microsoftonline.com/<tennantid>/oauth2/logout
But only doing this didn't do the job for all situations.
If I have my website open in more than one window/tab browser, the user gets invalid in Azure AD by invoking this url, but I can keep using my website at the other tab (it seems like the user in that tab session keeps still active).
This is similar to have my website in one tab and on another tab with the portal.azure.com open, and do logout in portal.azure.com which invalidate my user at Azure AD.
So my final solution was a mix of both
logout: function(req, res) {
req.logout();
res.redirect('https://login.microsoftonline.com/<tennantid>/oauth2/logout');
}
This does logout my user in the request and invokes logout authentication in Azure AD.
One can still add a redirect uri at logout url param ?post_logout_redirect_uri=
/oauth2/logout?post_logout_redirect_uri=<your website>
Looking at the code for Azure xplat they don't seem to call an explicit logout function, instead they simply delete all of the relevant client side tokens.
If there are no local tokens you can't be logged in!

Resources