Set callback URL for iOS apps in an Express application - node.js

I have an Express app that signs the user into Google using passport-google-oauth20, with the callback route: https://(hosturl)/auth/google/redirect.
I am trying to use this route to call my app after logging in using a ASWebAuthenticationSession and then get it to dismiss itself. I have already set my URL scheme in info.plist.
So far I have tried
api.get('/google/redirect', passport.authenticate('google'), (req, res) => {
res.status(301).redirect('com.googleusercontent.apps.<client id>');
});
which sends me to https://(hosturl)/auth/google/redirect/com.googleusercontent.apps.<client id>,
and
api.get('/google/redirect', passport.authenticate('google'), (req, res) => {
res.status(301).redirect('../../../com.googleusercontent.apps.<client id>');
});
which sends me to https://(hosturl)/com.googleusercontent.apps.<client id>

I have solved the issue, the redirect should be:
api.get('/google/redirect', passport.authenticate('google'), (req, res) => {
res.status(301).redirect('com.googleusercontent.apps.<client id>://');
});
The final '://' allows Express to recognise it as an external.

Related

Is there a mechanism to force express redirect to use host paths?

I have the following code snippet made with express js
import serverless from 'serverless-http'
import express from 'express';
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/api/info', (req, res) => {
res.send({ application: 'sample-app', version: '1.0' });
});
app.get('/jump', (req, res) => {
res.redirect('/api/info');
});
app.get('/explicit-jump', (req, res) => {
res.redirect('/dev/api/info');
});
app.post('/api/v1/getback', (req, res) => {
res.send({ ...req.body });
});
export default serverless(app)
If I deploy that code with serverless probably I will get an endpoint like https://my-api.some-region.amazonaws.com/dev/
Now if I try to reach the endpoint that redirect without the '/dev' path (/jump), I will get forbidden because is trying to reach https://my-api.some-region.amazonaws.com/api/info.
The one that set the path explicitly (/explicit-jump) works fine.
Fixing this single case is easy but I'm in the context of using an external app boilerplate (shopify express app) that has an incredible amount of redirects, really a high number.
I tried using a middleware that rewrites the urls when redirects:
app.use((req, res, next) => {
const redirector = res.redirect
res.redirect = function (url) {
console.log('CHANGING: ' + url);
url = url.replace('/api', '/dev/api')
console.log('TO: ' + url);
redirector.call(this, url)
}
next()
})
But I have the feeling that this is a brute force idea and actually it worked only in some occasions, somehow there are still redirects that goes to the base url ignoring the '/dev' path.
Is there a way I could fix this in a reasonable way so all redirects use the host in where the function is running?

How to redirect to variable link after authentication?

I'm working on a notes app , where people can keep their notes save (using express).
I want to add google authentication and for that I'm using passport.
My routs are -
/notes/:userId => for home page
http://localhost:8080/login/google/redirect => Authorized redirect URL
I'm also using a middleware isLoggedIn for checking if the user is loged in or not.
My middleware code -
module.exports.isLoggedIn = (req, res, next) => {
if(!req.user ){
req.flash('error', 'User must be signed-In');
return res.redirect('/login');
}
next();
}
In this I'm checking if the req have user property which passport atomatically adds while login using passport.autheticate() .
But now when i'm login using Google I need to use a fixed redirect URL. So how i redirect user to notes/:userId after authentication.
I tried using req.redirect in my redirect URL
router.get("/login/google/redirect", passport.authenticate('google', {failureRedirect: '/register'}),
async (req, res) => {
let userId = req.user._id;
res.redirect(`/notes/${userId}`);
});
but can't able to pass my middleware isLoggedIn.
How can I make this possible ?
Use isLoggedIn as /notes/:id route's middleware.
router.get("/notes/:id" , isLoggedIn, async (req, res) => {
// your logics code
});

How to have same backend for Flutter mobile app as of nodeJS website?

I already have a website with nodeJS and EJS templating engine. I know I should configure my server to return data in JSON format in order to have a backend for the flutter app.
I don't have much computer background and I'm a bit confused.
Here is what I'm doing in my website codes.
router.get("/", (req, res) => {
res.render("home", someData)
})
Just created different route for website and flutter application.
Route for website :
router.get("/api/web", (req, res) => {
res.render("home", someData)
})
Route for mob-application :
router.get("/api/app", (req, res) => {
//send response
})

Express with ReactJS not updating get function

I have an express/react app which runs just fine, it is a single-page app. I needed to make some changes on the server side regarding authentication, but I noticed that running the express server my app was not serving the updated .get function. Any thoughts on why this might be happening?
Old function
app.get('/app/', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'))
})
New function:
app.get('/app/', async (req, res) => {
const authorized = await checkSession(req)
if (!authorized) { res.redirect('/login'); return}
res.send("OK")
})
I suppose I should get a plain OK as a response in the browser, but even changing the server port, browser or anything I can think of I get the old page. Any help is much appreciated.
Remove the trailing slash on the first parameter of app.get():
app.get('/app', async (req, res) => {
const authorized = await checkSession(req)
if (!authorized) { res.redirect('/login'); return}
res.send("OK")
})
try to remove async/await because when you use this checkSession return one promise and continue to execute the rest os the code in this case you have to wait the return of checkSession before verify if is authorized.

How to log out from basicAuth (Express)

I'm trying to set up a web server using express. To access this server, users have to authenticate and for that, I use the basicAuth() middleware provided by Express. It works perfectly, except that I do not know how to log out once I logged in ! I have to close my browser to disconnect, but instead I would like to have a "disconnect" page which would redirect towards the "login" page (this one with the hideous form used to log in...).
Does anyone has an idea ?
Thanks per advance
PS : I apologize for my pathetic English :)
Express' basicAuth uses HTTP Basic Authentication whose implementation doesn't need HTML pages, cookies nor session ids. Its main drawbacks are its not secure and, our concern here, there is no mechanism in the spec for the server to instruct the browser to log out.
express.basicAuth() calls require(blah-blah/connect/lib/utils).unauthorized() which sends a 401 status with header 'WWW-Authenticate: Basic realm="..."'. The browser handles the authentication window and from then on sends a header like 'Authorization: Basic YmFzaWM6YmFzaWM=' which contains the username and password.
(express.basicAuth is not secure, especially over HTTP, because you can get the username:password with
new Buffer('YmFzaWM6YmFzaWM=' , 'base64').toString()
which gives basic:basic in this case.)
Our problem is the HTTP spec does not provide a way to stop that header being sent. A workaround for HTTPS is to redirect the user to a URL on the same domain having incorrect credentials.
The HTTP workaround I use for Express V3 can be used with app.use(express.basicAuth(...)). I find this easier to use than other solutions which require a call to middleware in every secured route, e.g. app.get('/secure', checkAuth, function (req, res) {...}).
Here is a working example.
var express = require('express'),
http = require('http'),
app = express();
app.use(express.favicon()); // prevent interference during test
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'winter is coming' }));
app.use(function (req, res, next) {
if (!req.session.authStatus || 'loggedOut' === req.session.authStatus) {
req.session.authStatus = 'loggingIn';
// cause Express to issue 401 status so browser asks for authentication
req.user = false;
req.remoteUser = false;
if (req.headers && req.headers.authorization) { delete req.headers.authorization; }
}
next();
});
app.use(express.basicAuth(function(user, pass, callback) {
callback(null, user === 'basic' && pass === 'basic');
}, '***** Enter user= basic & password= basic'));
app.use(function (req, res, next) {
req.session.authStatus = 'loggedIn';
next();
});
app.use(app.router);
app.get('/secure', function (req, res) {
res.send([
'You are on a secured page.',
'<br>',
'Refresh this page without having to log in again.',
'<br/>',
'Log out.'
].join(''));
});
app.get('/logout', function (req, res) {
delete req.session.authStatus;
res.send([
'You are now logged out.',
'<br/>',
'Return to the secure page. You will have to log in again.',
].join(''));
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000. Point browser to route /secure');
});
P.S. Your English is excellent.
For express.js 4 and basicAuth, you can use this method:
app.get('/logout', function (req, res) {
res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return res.sendStatus(401);
});
Adding to wyllman, the 401 code is Unauthorized.
You can simply respond with res.status(401).send('Logged out')
or
app.get('/logout', function (req, res) {
res.status(401).send('Logged out')
//or res.status(401).end() if you don't want to send any message
});
I've confirmed that redirecting the user to a /logout page with an http code 401 and html with <a> element links to /login works.

Resources