Cannot Get Prop Of NextRequest - javascript

I'm trying to MiddleWare With Next.js's Middleware and JWT.
When I console.log cookies and typeof cookies variable im getting on console:
{
token: 'token='myToken'; Path=/'
}
object
Here is my code:
import { NextRequest, NextResponse } from "next/server";
import { verify } from "jsonwebtoken";
const SECRET = process.env.SECRET;
export function middleware(req, res) {
const cookies = req.cookies;
const url = req.url;
if (url.includes("/admin")) {
console.log(cookies)
console.log(typeof cookies)
}
return NextResponse.next();
}
But when i try to get token prop like cookies.token, i got undefined
Any idea of what's going on?

Funny Answer:
I just need to use get method for get specified prop
const cookies = req.cookies.get('token');

Related

How to Export a Variable to Another file?

const ForgotPassword = ({ ...others }) => {
const theme = useTheme();
const { token } = useParams()
const handleSubmit = async(values) => {
console.log('load')
try {
const response = await axios.post(`http://localhost:3001/auth/reset/${token}`, {
password: values.password
});
if (response.data.msg === 'Password reset token is invalid or has expired') {
console.log(response)
} else {
// success message
}
} catch (err) {
console.error(err);
console.log("Something went wrong. Please try again later.")
}
console.log('not load')
};
return (
//...Content...
);
};
export default ForgotPassword;
I need to export token to use in other files how to do ?
I tried like this
export const token = useParams().token;
export const Token = token
etc ..
I'm new to this, could anyone tell me how to export token?
You can't export token directly because it's a local variable and is not available to export at the start of your app. Depending on where token needs to be accessed, you can pass it to a child component with a prop. If this fits your use case, it'll be the easiest method.
If you instead need to access the data from adjacent or parent components, you can set up an application store and access it from parent components. Something like React Redux will do this for you. Take a look at the React Redux Quick Start page for details on how that might work. This is my preferred method, but you can also use React Context instead of an external library to accomplish the same task.

ExpressJwt is not a function

I'm trying to write user authorization middleware. I use this function to validate and verify authorization later on.
I have done yarn add express-jwt.
auth.js code:
const SECRET = 'secret-message';
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const compose = require('composable-middleware');
function sign(user) {
return jwt.sign({
_id: user._id,
}, SECRET, {
expiresIn: 60 * 60
});
}
function sendUnauthorized(req, res) {
console.log(req.headers.authorization);
console.log(req.user);
res.status(401).json ({ message: 'Unathorized' });
};
const validateJwt = expressJwt({
secret: SECRET,
fail: sendUnauthorized,
getToken(req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.access_token) {
return req.query.access_token;
}
return null;
}
});
And the error is:
const validateJwt = expressJwt({
^
TypeError: expressJwt is not a function
I'm stuck on this error and can't go any further. I really need some advice.
As the error says, expressJwt is not a function. The logical next step would then be to check what it is instead, and at the same time to recheck your assumption of it being a function (why do you think that?) and looking for sources for that, for example by checking the docs of the package.
You will find that a) it's an object with { expressjwt: <some function here> }, and b) that the docs show an example that uses destructuring (var { expressjwt: jwt } = require('express-jwt')) which you don't do.
Both of these findings should point you to the fact that your assumption of the module's default export being a function is wrong and it's instead an object with property expressjwt which is the function you are looking for, so you could fix your code by using destructuring on the import as follows:
const { expressjwt: expressJwt } = require('express-jwt');
(Alternatively, using expressJwt.expressjwt(...) would have worked too, of course, but I think it looks quite ugly and is unnecessarily verbose.)

How to use cookie inside `getServerSideProps` method in Next.js?

I have to send current language on endpoint. But getting language from Cookie returns undefined inside getServerSideProps.
export async function getServerSideProps(context) {
const lang = await Cookie.get('next-i18next')
const res = await fetch(`endpoint/${lang}`)
const data = await res.json()
return {
props: { data },
}
}
export default Index;
What is the proper way to get cookie inside getServerSideProps?
You can get the cookies from the req.headers inside getServerSideProps:
export async function getServerSideProps(context) {
const cookies = context.req.headers.cookie;
return {
props: {},
};
}
You could then use the cookie npm package to parse them:
import * as cookie from 'cookie'
export async function getServerSideProps(context) {
const parsedCookies = cookie.parse(context.req.headers.cookie);
return { props: {} }
}
To avoid having to parse the cookies string from context.req.headers.cookie, Next.js also provides the cookies as an object which can be accessed with context.req.cookies.
export async function getServerSideProps(context) {
const lang = context.req.cookies['next-i18next']
// ...
}
From getServerSideProps documentation:
The req in the context passed to getServerSideProps provides built in
middleware that parses the incoming request (req). That middleware is:
req.cookies - An object containing the cookies sent by the request.
Defaults to {}
You can use parseCookies function with cookie package
import cookie from "cookie"
function parseCookies(req){
return cookie.parse(req ? req.headers.cookie || "" : document.cookie);
}
And then get access like that.
export async function getServerSideProps({ req} ) {
const cookies = parseCookies(req);
// And then get element from cookie by name
return {
props: {
jwt: cookies.jwt,
}
}
}
If you are using Axios this is very simple
This will work inside getServerSideProps method. You can't get access to the cookie by using withCredentials because this is on the server.
const { token } = context.req.cookies;
const response = await axios.get('/staff/single', {
headers: { Cookie: `token=${token};` },
});
or try (This will work on the client)
const response = await axios.get('/staff/single', {
headers: { withCredentials: true },
});
how are you doing?
you can use Something like this :
export async function getServerSideProps(context) {
console.log(context.req.cookies)
}
so easy and so beautifuly!

Sync store with cookies in nuxtServerInit - NuxtJS

I'm using NuxtJS's auth module and trying to get the Bearer token and a custom cookie that contains a sessionType on nuxtServerInit so I can update the store with a mutation, but it only works when I reload the page.
If I close the browser and go directly to my app url, I keep getting undefined for auth._token.local because nuxtServerInit executes before the cookies are ready.
My code in store/index.js looks like this:
export const actions = {
async nuxtServerInit({ commit, dispatch }, { req }) {
// Parse cookies with cookie-universal-nuxt
const token = this.$cookies.get('token')
const sessionType = this.$cookies.get('sessionType')
// Check if Cookie user and token exists to set them in 'auth'
if (token && user) {
commit('auth/SET_TOKEN', token)
commit('auth/SET_SESSION_TYPE', user)
}
}
}
I'm using nuxt-universal-cookies library.
What's the way to execute the action after the cookies are loaded on the browser?
Having it work with F5 and not by hitting enter makes me suspect that it just works sometimes and sometimes it doesn't, because F5 and Enter should trigger same behaviour on Nuxt (apart from some cache headers).
The only suspicious thing about you code is the usage of an async function when the function is not returning or awaiting any promise.
So you either await for an action
export const actions = {
async nuxtServerInit({ commit, dispatch }, { req }) {
// Parse cookies with cookie-universal-nuxt
const token = this.$cookies.get('token')
const sessionType = this.$cookies.get('sessionType')
// Check if Cookie user and token exists to set them in 'auth'
if (token && user) {
await dispatch('SET_SESSION', {token, user})
//commit('auth/SET_TOKEN', token)
//commit('auth/SET_SESSION_TYPE', user)
}
}
}
or you remove the async from the declaration
export const actions = {
nuxtServerInit({ commit, dispatch }, { req }) {
// Parse cookies with cookie-universal-nuxt
const token = this.$cookies.get('token')
const sessionType = this.$cookies.get('sessionType')
// Check if Cookie user and token exists to set them in 'auth'
if (token && user) {
commit('auth/SET_TOKEN', token)
commit('auth/SET_SESSION_TYPE', user)
}
}
}
I've had the same issue and found out that nuxtServerInit is triggered first before the cookie was set like via a express middleware.

Nuxt auth update auth on custom requests

From nuxt auth website I saw this:
setUserToken(token)
Returns: Promise
Set the auth token and fetch the user using the new token and current strategy.
TIP: This function can properly set the user after registration
this.$auth.setUserToken(token)
.then(() => this.$toast.success('User set!'))
Tried to use it and it said method is undefined, looked up in the source files and none of methods are like this one.
I am not very good with this but, how would I set user and token with nuxt/auth module after registration or anything but login/loginWith?
If there is no option for that why is it there on documentation?
I would also need to know if I need to create custom auth do I need to use both cookies and localstorage or just one of them?
It says that cookies are used for server side and storage for client side.
Can I use just cookies and on nuxtServerInit get cookie for token and set token and user data fetched by api within vuex store? Then use it from there if it is needed?
Nuxt/auth module hurt my brain so long and today I created custom module:
First I have this store structure:
store/
-- index.js
-- mutations.js
-- actions.js
-- state.js
-- getters.js
middleware/
-- redirectIfAuth.js
-- redirectIfNotAuth.js
layouts/
default.vue -> has redirectIfNotAuth.js
guest.vue -> has redirectIfAuth.js
pages/
-- login/
---- index.vue -> uses guest.vue as layout
-- dashboard/
----- index.vue -> uses default.vue as layout without declaration
Inside Index.js I have:
import state from './state'
import * as actions from './actions'
import * as mutations from './mutations'
import * as getters from './getters'
export default {
state,
getters,
mutations,
actions,
modules: {}
}
Inside State.js I have:
export default () => ({
user: null,
token: null,
headers: null
})
Inside Actions.js I have:
const cookieparser = process.server ? require('cookieparser') : undefined
// importing server based cookie library
export async function nuxtServerInit ({ commit }, { req, res }) {
// If we have any axios requests we need to add async/await
// And since this works on server mode, we don't need to check is it server
let token = null
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie)
try {
token = parsed.authToken
} catch (e) {
console.log(e)
}
}
// If we have token within cookies we get user data from api and we pass Autorization headers with token
if (token !== null && token !== false) {
await axios.get('/api/auth/me', {
headers: {
'Authorization': token
}
}).then((response) => {
// If we get user data we set it to store
commit('setUser', response.data.data)
commit('setToken', token)
commit('setHeaders', token)
}).catch((error) => {
// If we get error, we should logout user by removing data within cookies and store
// Additionally you can create specific code error on backend to check if token is expired or invalid
// and then check for status code and then remove data
commit('setUser', null)
commit('setToken', null)
res.setHeader('Set-Cookie', [`authToken=false; expires=Thu, 01 Jan 1970 00:00:00 GMT`])
// This is only way I found useful for removing cookies from node server
console.warn(error)
})
}
}
Inside Mutations.js I have:
export const setToken = (state, payload) => state.token = payload
export const setUser = (state, payload) => state.user = payload
export const setHeaders = (state, payload) => {
state.headers = {
headers: {
'Authorization': payload
}
}
}
Inside Getters.js I have:
export const getUser = (state) => state.user
export const getToken = (state) => state.token
export const getHeaders = (state) => state.headers
Second I created two middlewares and it seems like nuxt middlewares work on both server and client sides, so I needed to require both libraries for server and client side Then I checked which side it is and then try to get token for further investigations If you include and don't check for server and client but use one of them, your templates wont render but show undefined errors for req on client instead and on server it wont show anything.
Inside redirectIfAuth.js I have:
const cookieparser = process.server ? require('cookieparser') : undefined
const Cookie = process.client ? require('js-cookie') : undefined
export default function ({ app, redirect, req }) {
let token = null
if (process.server) {
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie)
try {
token = parsed.authToken
} catch (e) {
console.log(e)
}
}
} else if (process.client) {
token = Cookie.get('authToken')
}
if (token && token !== false) {
app.store.commit('setToken', token)
app.store.commit('setHeaders', token)
if (app.store.state.user) {
if (app.store.state.user.roles.includes('customer')) {
return redirect({
name: 'customer-slug',
params: { slug: app.store.state.user.username }
})
} else if (app.store.state.user.roles.includes('admin')) {
return redirect({
name: 'dashboard'
})
} else {
return redirect({
name: 'index'
})
}
} else {
return redirect({
name: 'index'
})
}
}
}
Inside redirectIfNotAuth.js I have:
const cookieparser = process.server ? require('cookieparser') : undefined
const Cookie = process.client ? require('js-cookie') : undefined
export default function ({ app, redirect, route, req }) {
let token = null
if (process.server) {
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie)
try {
token = parsed.authToken
} catch (e) {
console.log(e)
}
}
} else if (process.client) {
token = Cookie.get('authToken')
}
if (token === null || token === false) {
return redirect({
name: 'login',
query: {
redirect: route.fullPath
}
})
}
}
Now we use these middlewares within pages or layouts as:
export default {
middleware: ['redirectIfAuth']
}
Or
export default {
middleware: ['redirectIfNotAuth']
}
Login:
async login () {
if (this.form.email !== '' && this.form.password !== '') {
await this.$axios.post('/api/auth/login', this.form).then((response) => {
this.$store.commit('setUser', response.data.data)
this.$store.commit('setToken', 'Bearer ' + response.data.meta.access_token)
this.$store.commit('setHeaders', 'Bearer ' + response.data.meta.access_token)
Cookie.set('authToken', 'Bearer ' + response.data.meta.access_token, { expires: 365 })
// Cookie.set('authUser', response.data.data, { expires: 365 }) if you need user data within cookies
if (this.$route.query.redirect) {
this.$router.push(this.$route.query.redirect)
}
this.$router.push('/')
})
}
}
Logout:
async logout () {
await this.$axios.post('/api/auth/logout', {}, this.headers)
// Cookie.remove('authUser') if exists
Cookie.remove('authToken')
this.$router.push('/')
}
I hope this helps someone or someone get idea from this to make something else. I had million problems with official nuxt auth and only this helped me sort things out...

Categories

Resources