I'm building a SPA that will be sitting in a WebAPI/OWIN app (that will be hosted in IIS) that currently has no MVC components what so ever and the / route will just be index.html.
The whole site will need you to log into Azure AD before you can do anything and we'll then pass a bearer token to the WebAPI calls that are made.
How do you make every request to a static file (or at least, every HTML file) require you to be logged in?
I will tell you how I did it, and how it works for me.
I am using windows authentication, and here is how I configured it:
OwinHttpListener listener = appBuilder.Properties[typeof(OwinHttpListener).FullName] as OwinHttpListener;
listener.Listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
Then, according to this stackoverflow answer, put the following code between your auth middleware (or the auth code like the above code) and the components you want to protect. It will check to ensure that each request is authenticated.
app.Use(async (context, next) =>
{
var user = context.Authentication.User;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
context.Authentication.Challenge();
return;
}
await next();
});
I haven't tested this, but it is what I'd try first so I'm hoping it puts you on the right track.
Configure your app so OWIN is serving all static files via the StaticFilesMiddleware. This article talks about how to do that
Before you register the static file middleware (with the .UseStaticFiles extension method) create and register your own RequireAuthenticationMiddleware that checks if the request is authenticated and if it isn't returns the appropriate response (401, 403 or whatever). You'll want to register this RequireAuthenticationMiddleware after you configure the OWIN Auth middleware so that the auth details are in the OWIN context.
I haven't attempted that using OWIN middleware yet, but you could always fall back to using a HTTP module that checks for the presence of your auth cookie or bearer token?
Related
I'm using firebase to sign in my users on my node js app. I would like to see if the user is authentificated or not and after it redirect to the page I want (login if it not logged or dashboard).
But when I redirect user (if it not logged previously or session expires) it's looping on the same page (send redirect of the login page everytime when I'm on login page).
My function that I use actually :
function authenficated (req, res, next) {
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log("connected" + " " + user.uid);
next()
} else {
console.log("disconnected")
res.redirect('/') //loop on / page
next()
}
});
}
I would like a function that provides if my user is logged or not, if it logged my node backend return to /dashboard or other pages that I want and if not it cannot access to dashboard and it return automatically to / or /login
I specify I don't use React or Vue, I use simply EJS to display my pages
Thanks for all
This function/sdk is meant for frontend applications and not backend apps. You need to the admin sdk for that. You can use cookies and the admin sdk provides a function to create cookies. After a signin you attach the cookie to the headers and it will be send by the browser on every request. If the cookie header is empty than you know the user isn't signed in. To logout a user you can add a head method to clear the cookie.
To use backend function you need to use the admin sdk. This function is a front end function (web sdk ).
You can use onAuthStateChanged on the front end and redirect them from the front end. Remember onAuthStateChanged will fire on every page load.
OR implement cookies like the previous comments.
OR
Send the id token from the client via http request (fetch or axios) and verify server side using the admin sdk. Here is the specific link. This solution would require you to load something on the front end though and then send a http request to the backend, verify, then send protected resources after.
Cookies on the other hand are sent to the backend with every request, so if no cookie is present on the page load request then obviously there is no user. Or if the below function fails then server wont send protected resources. (this is explained in the link above for cookies)
getAuth().verifySessionCookie(sessionCookie, true /** checkRevoked */)
Okay, so atm i have a frontend application built with Nuxt JS using Axios to do requests to my REST API(separate).
If a user does a search on the website the API URL is visible in XMLHttprequests so everyone could use the API if they want to.
What is the best way of making it so that only users that search through my website gets access to the API and people that just directly to the URL gets denied. I suppose using some sort of token system, but what is the best way to do it? JWT? (Users never log in so there is no "authentication")
Thanks!
IMO, you CANNOT block other illegal clients accessing your
backend as you describe that the official client and other illegal have the same knowledge about your backend.
But you can make it harder for illegal clients to accessing your backend through some approach such as POST all requests, special keys in header, 30-minutes-changed token in header and server-side API throttling by client IP.
If the security of the search API is really important, authenticate it by login; if not, just let it go since it is not in your critical path. Let's focus on other important things.
I'm in the same "boat" and my current setup is actually in VueJs but before even come to StackOverflow I developed a way to actually, the frontend calls the server and then the server calls the API, so in the browser, you will only see calls to the server layer that, the only constraint is that the call must come from the same hostname.
backend is handled with expressJs and frontend with VueJs
// protect /api calls to only be originated from 'process.env.API_ALLOW_HOST'
app.use(api.allowOnlySameDomainRequests());
...
const allowHostname = process.env.API_ALLOW_HOST ||'localhost';
exports.api = {
...
allowOnlySameDomainRequests: (req, res, next) => {
if(req.url.startsWith('/api') && req.hostname === allowHostname) {
// an /api call, only if request is the same
return next();
} else if (!req.url.startsWith('/api')) {
// not an /api call
return next();
}
return res.redirect('/error?code=401');
},
...
};
In our case, we use Oauth2 (Google sign through passportJs) to log in the user, I always have a user id that was given by the OAuth2 successful redirect and that user id is passed to the API in a header, together with the apikey... in the server I check for that userid permissions and I allow or not the action to be executed.
But even I was trying to find something better. I've seen several javascript frontend apps using calls to their backend but they use Bearer tokens.
As a curious user, you would see the paths to all the API and how they are composed, but in my case, you only see calls to the expressJs backend, and only there I forward to the real API... I don't know if that's just "more work", but seemed a bit more "secure" to approach the problem this way.
I am making a very basic REST API using Express 4 (express.Router). How can I secure this API in a simple way?
I do not need to authenticate individual users so most of the strategies that I have found seem like overkill. I am just trying to moderately secure the API so I am hopefully the only one using it. Not sure what strategy I can use to pass something from the client to identify myself. Thanks!
I will be accessing this API from a web page as well as mobile client (with Ionic) and hosting the app on Google Clouds App Engine.
You could use a header or a query string to authenticate. For example, setup a middleware on Express to check if the header X-TOKEN contains a string of your choice.
Here's a code which you can use to do that:
function checkAuthHeader (req, res, next) {
let token = req.headers['X-TOKEN'];
if (token && token == "RANDOM_GENERATED_STRING") {
next();
} else {
res.status(403).end('Unauthorized.')
}
}
Then you can use this function as a middleware like this (make sure you place it before declaring your routes):
app.use(checkAuthHeader)
You should be using environmental variables instead of a hard-coded string as well. I just used a hard coded one for demonstration.
I am using Instagram's API which requires OAuth2 have some questions regarding best practice for setup. For more details here: https://www.instagram.com/developer/authentication/
So a user clicks on a login button and I give a redirect href.
Log In
They then receive a popup sign in, and they have the option of signing in or not. They are then redirected and '?code=zzzzzzz'is appended to the url: "http://localhost:8080?code=zzzzzzz"
Then the instructions read:
Now you need to exchange the code you have received in the previous step for an access token. In order to make this exchange, you simply have to POST this code, along with some app identification parameters, to our access_token endpoint.
But how should I do this? I'm using Express on the backend. To serve the frontend I use this line:
var static_path = path.join(__dirname, './../build');
It isn't an API route, so I can't use the normal
app.get('/?code=zzzzzzz', function(req, res) {...}).
So how can I use the code that I received in the params?
You must change your redirect_uri on isntagram to something like:
/auth/instagram/callback
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:8080/auth/instagram/callback&response_type=code
Then you can get your code with req.query.code from inside the controller.
For posting the code to isntagrams API use "request" library for nodejs
I have a startup module in angularjs. This module is just to login and have public information (login, prices, newsletter...). I have many roles and for each role, i have an app (angular module). I made this architecture because i have complex module for each role and it was impossible to put all roles in one module.
So, for login, i use jsonwebtoken in node like this :
var token = jwt.sign(user, config.secureToken, { expiresInMinutes: 20*5});
res.json({ token: token, user: user });
It works perfectly. I can login into my app. After that, i have to propose a list of roles to redirect to the right module.
In angular, I have AuthHttp service that adds security headers (with token) to call rest service with $http.
How can i redirect to 'mydomain:port/anotherModule' with $location or $http ?
With this code in nodejs :
app.get('/secondModule', expressJwt({secret: config.secureToken}), function (req, res) {
res.render('restricted/secondModule/index.html');
});
NodeJs sends an html code in response and does'nt redirect...
And if i do this in my angular controller :
location.href = route;
i have this result on nodejs console :
Error: No Authorization header was found
I am not sure about the libraries you are using, but issue seems that you are loosing the token because you navigate to a altogether new page.
Based on your auth library you need to pass the token that you get after auth from one page to another.
The options here are to either use browser sessionStorage or querystring to pass the token along and at it back to the http header collection on the new page (module)
This is an old post but I recently took a long time to figure this out. I may be wrong but I believe nodeJS/expressJS can't read the token from the session storage. I believe you will need to pass the token via the request header using AngularJS.
This depends on the front end that you are using. For me, I am using AngularJS and I have to do something like this.
angular.module('AngularApp').factory('authFactory',
function($window){ //the window object will be able to access the token
var auth = {};
auth.saveToken = function(token){
$window.localStorage['token_name'] = token; //saving the token
}
auth.getToken = function(){
return $window.localStorage['token_name']; //retrieving the token
}
return auth;
}
.service('authInterceptor, function(authFactory){
return { headers: {Authorization: 'Bearer "+ authFactory.getToken()}
} //the last line gets the retrieved token and put it in req.header
Then, you just need to include 'authInterceptor' in all the http methods when you communicate with the backend. This way, nodeJS will be able to pick up the token.
You can see the Authorization field in req.header if you use the chrome developer tool and look at the Network tab. Hope this helps.