display data on page when user is auth, express , jwt, cookie-parser - express

I have simple application where user can register and login in his acc, now i want display user login on page, how i can get data from db about user that authinticated now
i also use mongodb and moongose as database
this register sistem
router.post('/register',async (req,res)=>{
const {login,mail,password} = req.body
bcrypt.hash(password, 10).then((hash) =>{
User({login:login,password:hash,mail:mail}).save()
})
res.redirect('/login')
})
this is login sistem
router.post('/',async (req,res)=>{
const {mail, password } = req.body
const user = req.body
console.log(user)
const isUserExist = await User.findOne({mail:mail})
const UserPwdCorrect = isUserExist.password
if(!isUserExist){
console.log('Логин гавно')
} else{
bcrypt.compare(password,UserPwdCorrect).then((match)=>{
if(!match){
console.log("Пароль говно")
} else{
const accessToken = createToken(user)
res.cookie("token",accessToken,{
maxAge:60*60*24*30*1000
})
res.redirect('/')
}
})
}
})
and this is what i did in jwt.js file
const {sign,verify} = require("jsonwebtoken")
const createToken = (user) =>{
const accessToken = sign({login: user.login, isAdmin:user.idAdmin,id:user.id},"jwt-secret")
return accessToken
}
const validateToken = (req,res,next) =>{
const accessToken = req.cookies["token"]
console.log(accessToken)
if(accessToken){
try {
const validtoken = verify(accessToken,"jwt-secret")
if(validtoken){
req.authenticated = true
return next()
} else{
return next()
}
} catch(err){
console.log(err)
}
}
}

Here's one solution:
Pass in userID in the JWT token. When the user clicks on the profile page, send a POST request to an endpoint that accepts the token (in a header). The backend verifies the token, extracts the userID, makes the DB call, and finally returns the response.
An advantage to this approach is that your profile route is authenticated (i.e, the route is secure).

Related

Missing claims in payload of jwt token

As part of my login endpoint I return a generated token using the 'generateToken' function. The payload contains an object of claims(user.id and user.role). However when I log in and check the returned token I do not see any of the claims; just the 'created' and 'expires' values.
Login endpoint
async function findUserById(req, res){
let { email, password } = req.body;
try {
const user = await db.query("SELECT * FROM user_account WHERE email = $1", [email]);
if(!user.rows.length){
return res.status(401).json("Invalid crendential")
}
const validPassword = await bcrypt.compareSync(password, user.rows[0].password)
if(!validPassword){
return res.status(401).json("Invalid credential");
}
const token = await generateToken(user);
res.status(200).json({ user, email: user.email, token})
} catch (error) {
res.status(500).json({error: error.message})
}
}
generateToken function
const jwt = require("jsonwebtoken");
const secret = require("../config/secrets");
function generateToken(user){
const payload = {
subject: user.id,
role: user.role
};
const options = {
expiresIn: "30d"
};
return jwt.sign(payload, secret.jwtSecret, options)
}
module.exports = {generateToken};

Nextjs Auth0 get data in getServerSideProps

Im using Auth0 to authenticate users.
Im protected api routes like this:
// pages/api/secret.js
import { withApiAuthRequired, getSession } from '#auth0/nextjs-auth0';
export default withApiAuthRequired(function ProtectedRoute(req, res) {
const session = getSession(req, res);
const data = { test: 'test' };
res.json({ data });
});
My problem is when I'm trying to fetch the data from getServerSideProps I'm getting 401 error code.
If I use useEffect Im able to get data from api route.
Im trying to fetch the data like this:
export const getServerSideProps = withPageAuthRequired({
async getServerSideProps(ctx) {
const res = await fetch('http://localhost:3000/api/secret');
const data = await res.json();
return { props: { data } };
},
});
Im getting the following response:
error: "not_authenticated", description: "The user does not have an active session or is not authenticated"
Any idea guys? Thanks!!
When you call from getServerSideProps the protected API end-point you are not passing any user's context (such as Cookies) to the request, therefore, you are not authenticated.
When you call from useEffect it runs inside your browser, which attaches all cookies to the request, one of them is the session cookie.
You need to forward the session cookie that was passed to the getServerSideProps (by the browser) to the API call.
export const getServerSideProps = withPageAuthRequired({
async getServerSideProps(ctx) {
const res = await fetch('http://localhost:3000/api/secret', {
headers: { Cookie: ctx.req.headers.cookie },
// ---------------------------^ this req is the browser request to the getServersideProps
});
const data = await res.json();
return { props: { data } };
},
});
For more info.
#auth0/nextjs-auth0 has useUser hook. This example is from: https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/
// pages/index.js
import { useUser } from '#auth0/nextjs-auth0';
export default () => {
const { user, error, isLoading } = useUser();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>{error.message}</div>;
if (user) {
return (
<div>
Welcome {user.name}! Logout
</div>
);
}
// if not user
return Login;
};
Note that authentication takes place on the server in this model,
meaning that the client isn't aware that the user is logged in. The
useUser hook makes it aware by accessing that information in the
initial state or through the /api/auth/profile endpoint, but it won't
expose any id_token or access_token to the client. That information
remains on the server side.
Custom HOF:
// getData is a callback function
export const withAuth = (getData) => async ({req, res}) => {
const session = await auth0.getSession(req);
if (!session || !session.user) {
res.writeHead(302, {
Location: '/api/v1/login'
});
res.end();
return {props: {}};
}
const data = getData ? await getData({req, res}, session.user) : {};
return {props: {user: session.user, ...data}}
}
Example of using:
export const getServerSideProps = withAuth(async ({req, res}, user) => {
const title = await getTitle();
return title;
});

I am tring to make Static Model.findByCredentials. But it is not working for mongoose, Express login system?

userSchema.statics.findByCredentials = async (email, password) =>{
const user =await User.findOne({ email })
if(!user){
throw new Error("Unable to Login!")
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch){
throw new Error("Invalid to Login!!")
}
return user
}
const User = new mongoose.model("User",userSchema)
module.exports = User
In users i have set the routes properly too:
router.post("/users/login", async (req,res) => {
try{
const user = await User.findByCredentials(req.body.email, req.body.password)
res.send(user)
}
catch(err){
res.status(400).send()
}
})
But i get 400 Bad request error. The route is catching the error.
findByCredentials is not working?
What is my mistake??

Get localStorage in NextJs getInitialProps

I working with localStorage token in my next.js application. I tried to get the localStorage on page getInitialProps but, it returns undefined.
Here is an example,
Dashboard.getInitialProps = async () => {
const token = localStorage.getItem('auth');
const res = await fetch(`${process.env.API_URL}/pages/about`, {
headers: { 'Authorization': token }
});
const data = await res.json();
return { page: data };
}
For the initial page load, getInitialProps will run on the server
only. getInitialProps will then run on the client when navigating to a
different route via the next/link component or by using next/router. Docs
This means you will not be able to access localStorage(client-side-only) all the time and will have to handle it:
Dashboard.getInitialProps = async ({ req }) => {
let token;
if (req) {
// server
return { page: {} };
} else {
// client
const token = localStorage.getItem("auth");
const res = await fetch(`${process.env.API_URL}/pages/about`, {
headers: { Authorization: token },
});
const data = await res.json();
return { page: data };
}
};
If you want to get the user's token for the initial page load, you have to store the token in cookies instead of localStorage which #alejandro also mentioned in the comment.

Cannot Access themes.json using shopify api and nodejs

I am not able to access the themes.json of my development store using shopify api and nodejs.
Here is what I am doing:
app.get('/shopify/examplePage', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
// Verifying Cookie
if (state !== stateCookie) {
return res.status(403).send('Request origin cannot be verified');
}
// Verifying Hmac
if (shop && hmac && code) {
const map = Object.assign({}, req.query);
delete map['hmac'];
const message = querystring.stringify(map);
const generatedHash = crypto
.createHmac('sha256', apiSecret)
.update(message)
.digest('hex');
if(generatedHash !== hmac){
return res.status(400).send('HMAC verification failed');
}
// Appending Access Token to the shop Url
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code
};
// Making an API Request And getting an API response
request.post(accessTokenRequestUrl, {json: accessTokenPayload })
// Promise for Access Token Response
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// Request URL for Products
const apiRequestUrl = 'https://' + shop + '/admin/api/2019-04/themes.json'
console.log(apiRequestUrl);
const apiRequestHeader = {
'X-Shopify-Access-Token': accessToken
};
request.get(apiRequestUrl, { headers: apiRequestHeader })
.then((apiResponse) => {
let example = JSON.parse(apiResponse);
res.send(example);
// End API Response
res.end(apiResponse)
}).catch((error) => {
res.status(error.statusCode).send(error.error.error_descripton)
});
}).catch((error) => {
res.status(error.statusCode).send(error.error.error_descripton)
})
} else {
res.status(400).send('Required parameters missing');
}
});
There is this error showing that the access to {ngrok}.ngrok.io was denied while I can access product.json & shop.json with the help of same code
Denied means your API key doesn’t have access. If this is a public app you need to add read_themes to your scopes. If it is a private app you need to go to the app setup and add theme access.