Im working on a project, using firebase auth for login i.e. login with google; if logged in then redirect to /app where real functionalities of webapp exists.
login page js:
document.getElementById('login').addEventListener('click', e => {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
firebase.auth().currentUser.getIdToken(true).then(function(token) {
// make request to backend to get /app page where main app exists
axios.get('/app', {
headers: { 'Authorization': `Bearer ${token}` }
})
.then(res => {
console.log(res.data);
});
});
});
});
now my main motive is, user can't access pages other than / (landing page) without JWT token in header.
so here when user log in using login With google it will give token when logged in and then it will make req to backend with token and backend will return /app page pre-rendered!
PROBLEM: using this is code, when i make req to backend it just return HTML code in res.data BUT i want actual page!!
Axios is well and good to fetch data from my backend api but i cant figure out how to attach header and make req, And get page instead of source code in response;
Same problem is occurring everywhere in application. I just don't want users to access pages other than landing page without JWT in header!
backend: nodeJs
firebase auth
ejs template engine for view
EDIT:
meaning of returning source code is:
img of console log
any help, ideas or approach are welcome 🙏🏻
Login as before
Write the token into a cookie instead of the Authorization header
Redirect the browser to /app
In the backend read the cookie instead of the Authorization header
This way the browser will solve the problem for you by rendering the response. Using cookies is the usual way to implement a login without AJAX.
It's not possible to make a redirect and set the Authorization header.
Related
I am building a full-stack app with NestJS for the backend and Next.js for the frontend. I have added stateless authentication in NestJS using jwt and passport. Now, I want to add protected route in my Next.js app based on the authenticity of the jwt token that I received from my NestJS backend. What is the best way to achieve this? I want to add protected route for both server-side rendered and client-side rendered pages.
The term 'protected route' refers to being authorized to access certain resources from certain routes (or GraphQL resolvers), so these routes on the server (NestJS) need to check whether the JWT-token is valid and return an appropriate HTTP response. NestJS has built in Guards for that purpose, which return an 401-Unauthorized response in case the JWT is invalid.
So for client-side rendering, if you fetch these resources on your NextJS front-end and include the JWT in the request headers like this: Authorization: Bearer [token], you will know from the HTTP response whether the fetch was successful or not, which will let you either display the data or an error on the front-end.
A simple example for server-side rendering with getServerSideProps could worklike this:
After you Signin via your NestJS server, you set the JWT in a cookie which will be included in every request you make to your NextJS server (its a different server than your NestJS server if you host your NextJS app on vercel)
In getServerSideProps you parse the cookie (on the NextJS server) and add the parsed token to the headers of the request to your NestJS route.
const Component = ({data, authorized}) => {
return {authorized ? <div>Page Content</div> : <div>Log In to view this content</div>}
}
// this function gets called on the NextJS server whenever you visit a page.
// If you're logged in and have a cookie, the cookie will be inside context.req.headers.cookie
export async function getServerSideProps(context) {
// assuming you use the 'cookie' npm package
// and you did not sign the cookie on NestJS with a secret so it has a raw value
const cookies = cookie.parse(context.req.headers.cookie)
const token = cookies.token // assuming you named the cookie 'token' when you set it on your NestJS server
// assuming you use the 'axios' npm package
const response = await axios.get("NestJsServerUrl/route",
headers: {
'Authorization': `Bearer ${token}`
} )
const authorized = response.status != 401
return {
props: {
data: response.data
authorized
}
}
}
Now if you're signed in and you have a cookie with the name 'token' containing a valid token in your browser, your browser will first make a request to the NextJS server with that cookie. This cookie will be extracted and parsed in getServerSideProps on the NextJS server, and will then be used to fetch the resources on the NestJS server by adding it to the Authorization header. Based on the response, the NextJS server will render the page by using conditional rendering.
Let me know if it works.
I'm developing a web application, where the user is given a challenge from the web app that contains a URL to another website, where he's asked to sign-up.
The sign-up page is made using the sign-up flow in Azure AD B2C.
The response sent from my ASP.NET Core API looks like this:
var redirectUrl = Url.Action(nameof(SignupController.Return), "Signup");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
properties.Items[AzureAdB2COptions.PolicyAuthenticationProperty] = AzureAdB2COptions.SignUpPolicyId;
return Challenge(properties, OpenIdConnectDefaults.AuthenticationScheme);
The challenge is requested using Fetch API in Javascript, which looks like this:
fetch(`/api/invitations/${invitationId}`, {
method: 'PUT',
mode: 'cors'
}).then(response => {
// HTTP 301 response
if (response.redirected) {
console.log(response.url);
window.location.href(response.url);
}
})
.catch(function (err) {
console.log(err);
});
However I keep getting this error:
As far as I understand this is a server problem, but I suppose its on b2clogin? I can't really see how I'm supposed to update the CORS policy. I can easily access the fetch URL as shown above by clicking on it, but the javascript code itself cannot redirect to it. I'm sure it's just a simple fix. I hope someone will help.
I am not sure what you are trying to achieve here because of limited context. But, to fix this error, run below Azure CLI command in your Local:
az webapp cors add --resource-group myResourceGroup --name api-name --allowed-origins 'http://localhost:44315'
Check out more about CORS policies in App service here.
I'm working on a full stack project where users can create account, visit their profile, create blogs, read their blogs, delete their blogs etc. In order to perform all these tasks (except signup and login) the user has to be authenticated.
I'm done with the back end but i don't understand how do i send jsonwebtoken from the client side to the server side (i know how to send it from the server side). I know how to get tokens from the server and store them in browser's locaStorage but i don't know how to send them back to the server when i'm making request for reading blogs or deleting blogs or visiting back to my profile after reading all my blogs.
If i do this -
window.location.href = "/blogs";
then i won't be able to send authentication token or i should say i don't know how to send authentication token using this approach.
Here on stack overflow i read about this technique-
window.location.href = "/blogs?token=";
but i don't think developers uses this technique in their projects because as far as i know tokens are supposed to be sent through headers.
If i summarize my question i just want to know how do i send authentication token to the server as well as change the page for different routes for example a different page that shows all my blogs and another page that shows only my profile. If someone else who is not authenticated tries to visit profile route or blogs route, would get a 401 error.
It would be a great help if anyone could solve my confusion or suggest me a book or an article that solves my confusion.
I will try to make it simple. As an example, I will use code from one of my project.
First, you do not explain how you check and validate token on server-side. So to make explication more complete, I will provide some code.
On the server-side, I use a simple function to check each request received and depending on verification and validation process, I will update the request received before sending it to resolver.
NB: current code used Express
In my example, I store the token inside the request header Authorization field.
const isAuth = async (req, res, next) => {
const authHeader = req.get('Authorization');
// if is no authorization field in header, we call
if (!authHeader) {
req.isAuth = false;
return next();
}
const token = authHeader.split(' ')[1]; // `Bearer XXXXXXXXXXXXXXXXXXXXX...`
if (!token) {
req.isAuth = false;
return next();
}
// Here i decode the token
const decodedToken = jwt.verify(token, 'SomeSecretWord');
req.isAuth = true;
return next();
}
On each request received, we check if the header contain an authorization token, if yes, we validate and verify token. If validation is successfully completed, I update isAuth field inside request and set it to true.
app.use(isAuth);
Now you will be able to access the isAuth inside resolvers and return data based on its value (example: throw error if false);
So now, for the client-side, since we expect token to be store inside the headers Authorization field, we need to set it before sending request.
Be sure to already have the token save on client-side.
In my case, user need to login to receive a new token so he store the newly created token inside client-side storage.
Now before sending each request, access token from storage and updare request header with it.
const headers = {
Authorization: "Bearer XXXXXXXXXXXXXXXXXXXXXX",
};
const reqInit = {
method: 'GET',
headers: headers,
};
// send request using fetch
fetch('/someLocation', reqInit)
...
The problem I faced here, was to store the token between requests for a user session.
the easiest and secure way is to save it in the local or session cache (according to google after a small research) and access it on each request.
While creating the json web token on server-side you can specify a expirery so if token was not used for a certain time, it will be invalid and user will need to reauthenticating to receive an other token and save it in his client-side storage.
After some research, I decide to rewrite my backend with graphql (apollo-server
/ express) for server-side and apollo-client for client-side.
since apollo-client provides a library to manage local cache on client-side, it simplifies the task.
I hope I have answered your question and that can help you and sorry if I made a mistakes.
Add authorization header to your request
headers: {
"authorization": "Bearer your_token"
}
Its and example for adding header to ajax request.
I'm using MSAL lib for authorize my SPA.
Init:
msUserAgent = new Msal.UserAgentApplication(idApp, null, null, {});
Call loginPopup:
msUserAgent.loginPopup(['user.read'])
.then((res) => console.log(res))
.catch((err) => console.log(err));
after set my credentials, popUp not closing, but redirect to main page. Then and catch not called at all.
Issue on github about this: https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/174
After redirect, my URL (in popup) has id_token (jwt-token), but this page doesn't have initialized msUserAgent yet. It dynamically process, I initialize msUserAgent after user click (idApp getting from backend)
Question:
Can I get access_token when I have id_token (jwt-token) by using MSAL lib?
Thanks
for getting access_token need to do next:
On page where you are being redirected. You need to have loaded MSAL script
msUserAgent need to auto init after all scripts will be loaded
MSAL checking if JWT token present in uri (after redirect), and if it exists, immediately send silent request and get access_token and save to sessionStorage (you can change to localStorage in options)
I am just having fun with the new Firebase, but I'm struggling with auth system.
Because I'm trying to login user from options page of google extension, so I can't use signInWithPopup or Redirect method due (some) security reasons.
So I figure out possible solution. From options page I redirect user to my another page, where he can easily login with Firebase (by Facebook provider) - everything is OK - user obtain OAuth FB token and this page send message to extension to cache this token.
There lies the problem.
I have code like this:
firebase.initializeApp(FIREBASE_CONFIG);
var credential = new firebase.auth.FacebookAuthProvider.credential(token);
firebase.auth().signInWithCredential(credential)
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err.code);
})
This fire up POST request to https://www.googleapis.com/identitytoolkit/v3/relyingparty/ and in response I can clearly see the error:
message:"INVALID_REQUEST_URI"
This request is fired with requestURI payload, which is in mine situation:
chrome-extension://kefhjfjilmodblnpnekjleceapohasdf/options.html
When I tried to fire this request from terminal with CURL and I faked the requestURI with 'http://localhost' everything is OK and I got correct data.
Do you have any ideas, how can I achieve proper behavior?
Thanks a lot.
P.S: I'm using Firebase.js 3.0.5-rc.2