I am learning about Next.JS and React and was wondering if it is possible to get user details from the cookie storing the JWT.
I have managed to set the JWT as the cookie and can log it successfully and have also managed to decode it but can't find anything on how to get username, id, etc from it. Here's what I have so far:
import React from "react";
import App from "../components/App.js";
import cookie from "react-cookies";
import jwt_decode from "jwt-decode";
export default class Dashboard extends React.Component {
static async getInitialProps() {
const token = cookie.load("jwt");
return { token };
}
constructor(props) {
super(props);
this.state = props.token;
}
render() {
const current_user = jwt_decode(this.props.token, { header: true });
return (
<App>
<p>Username: {current_user.username}</p>
</App>
);
}
}
Ideally, i'd like to be able to set the cookie value to a user variable and extract properties from it, e.g. current_user.username. Unless i've got it completely wrong and have missed out something really important! Any help would be massively appreciated!
You can use this parseJwt function to extract the user data:
function parseJwt(token) {
if (!token) { return; }
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(window.atob(base64));
}
console.log(parseJwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'))
It will extract the data inside a jwt token and will return an object
You can use npm package. Simply run npm install jwt-decode in the cmd and use the following code:
import jwt_decode from "jwt-decode";
const token = "eyJ0eXAiO.../// jwt token";
const decoded = jwt_decode(token);
Related
I have an app that persists some values in a cookie. I know that there are other tools such as useState, useContext, etc... but this particular app works with a library that stores information in a jwt so I have to read certain values by fetching the jwt. I am porting the app from next.js 12 (with webpack) to next.js 13 (with turbopack).
I've already ported the app structurally to fit the app style routing of next.js 13. My pages all go in their individual folders with sub layouts WITHIN the app directory, and I have a master layout and homepage directly in the app directory.
The old code for my protected page in next.js 12 looked like this:
protected.tsx
import type { NextPage } from 'next';
import { GetServerSideProps } from 'next';
import { useContext } from 'react';
//#ts-ignore
import Cookies from 'cookies';
const Protected: NextPage = (props: any) => {
if (!props.authorized) {
return (
<h2>Unauthorized</h2>
)
} else {
return (
<div className="max-w-md">
<h1 className="font-bold">This is the Protected Section</h1>
</div>
)}
}
export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
const { id } = query
const cookies = new Cookies(req, res)
const jwt = cookies.get('<MY TOKEN NAME>')
if (!jwt) {
return {
props: {
authorized: false
},
}
}
const { verified } = <MY TOKEN SDK INSTANCE>.verifyJwt({ jwt })
return {
props: {
authorized: verified ? true : false
},
}
}
export default Protected
I have this page moved into it's own directory now.
"getServerSideProps" isn't supported in Next.js 13 https://beta.nextjs.org/docs/data-fetching/fundamentals. The docs say "previous Next.js APIs such as getServerSideProps, getStaticProps, and getInitialProps are not supported in the new app directory." So how would I change my code to work in Next.js 13?
P.S. I know what it looks like but this cookie IS NOT HANDLING USER AUTHENTICATION. I understand that someone could alter the cookie and gain access to the protected page. This is just a small piece of a larger app with other security mechanisms that I have in place.
import { cookies } from "next/headers";
this is next/headers.js cookie function
function cookies() {
(0, _staticGenerationBailout).staticGenerationBailout('cookies');
const requestStore = _requestAsyncStorage.requestAsyncStorage && 'getStore' in _requestAsyncStorage.requestAsyncStorage ? _requestAsyncStorage.requestAsyncStorage.getStore() : _requestAsyncStorage.requestAsyncStorage;
return requestStore.cookies;
}
this is making a request to the client side to get the cookie. In app directory, you are on the server and you can write this inside the component.
const cookie = cookies().get("cookieName")?.value
you can access to your cookie via "cookies-next" library.
pnpm i cookies-next
check this out : https://www.npmjs.com/package/cookies-next
I am building an app where the user connects to a server by entering the URL when logging in.
Each server provides an API and I can't hard-code the value for the BaseURL when creating the Axios client instance. I somehow need to globally store the URL and set it based on the user input in the login form.
So I would like to know what is a proper way to do this. I am really not sure what is the best approach to dynamically store a value that I can access when creating the API connection. Any ideas and best practice suggestions are welcome.
Here is the code for creating the API connection: client.js
import { create } from 'apisauce';
const api = create({
baseURL: "BASE_URL_FROM_USER_INPUT" + "server/odata/"
});
export default api;
This is how I use the API: users.js
import api from './client';
const getUsers = () => api.get("/users");
export default {
getUsers
}
This is how I will get my data:
import React, { useState, useEffect } from "react";
import usersApi from '../api/users';
const TestScreenAuthenticated = ({navigation}) => {
const [users, setUsers] = useState([]);
useEffect(() => {
loadUsers();
});
const loadUsers = async () => {
const response = await usersApi.getUsers();
setUsers(response);
}
...
};
export default TestScreenAuthenticated;
you can use the localStoreto store the baseUrl.
//save the value
localStore.setItem('baseUrl', value)
//read the value
localStore.getItem('baseUrl')
If you can use the .env file in your project and put the web service address there. This file is out of reach of the user viewing the site and will not be able to edit it
this link:
https://create-react-app.dev/docs/adding-custom-environment-variables/
I am building a FullStack App with React and Express.
I am using react-cookie.
After submit a form i set cookies in my browser then i render a new page in my application.
setCookie("jwt", `${data.jwt}`, {
path: "/"
});
setCookie("user", `${data.name}`, {
path: "/"
});
Then i want to read a cookie in that component and i do not know how can i do it.
So if someone have any idea how to do it please write below :)
Thanks :)
You can use the hook useCookies like this:
import { useCookies } from 'react-cookie';
const [cookies, setCookie, removeCookie] = useCookies(['cookie-name']);
const myCookie = cookies.get('cookie-name')
You could use much simpler way like this
(make sure you have installed react-cookie FIRST!)
import { useCookies } from 'react-cookie';
const [cookies, setCookie, removeCookie] = useCookies();
// set Cookie
setCookie('access_token','your_token_value_here')
// read cookie with
console.log(cookies.access_token)
How can i retrieve some data from a local json file i created in my folder? i´m using the following code:
class Intro2 extends Component {
render() {
async function getData() {
const usersData = await fetch("../articles.json");
const users = await usersData.json();
return users;
}
}
This doesn't seem to work for my local json file but if i use a url from git hub users for example its working?
many thanks
The error: main.chunk.js:332 Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
You shouldn't be using fetch.
Use import instead. This will ensure webpack doesn't bundle the json file.
But makes it available in the public directory.
const usersData = await import("../articles.json");
Fetch will never work because webpack won't serve your JSON file.
Not unless you put it in a the static or public folder.
I think if you're trying to read from your file system you won't be able to do it, because in at least some browsers, you will need to serve the file via a web server process.
But if you are trying to read from http://localhost:9000/articles.json the issue could be another thing.
Maybe you need the {mode:'no-cors'} param ?
fetch('../static/test.txt', {mode: 'no-cors'})
Else you could simply export it:
export const json = () => ({...})
and then import it to your file:
import {json} from '../json
Assuming the json is in the project's folder structure.
import React from "react";
import ReactDom from "react-dom";
import usersData from "../articles.json";
class Intro2 extends React.Component {
state = {
usersData: { ...usersData },
};
componentDidMount() {
// a place for promises
};
render() {
// where the jsx is rendered
return <div>Renders JSX with state {this.state.usersData.aKey}</div>;
}
};
or with react functional components
// Alternatively, use functional components:
import React from "react";
import usersData from "../articles.json";
function Intro2() {
const [usersData, setUsersData] = React.useState({ ...usersData });
return <div>Renders JSX with state {usersData.aKey}</div>;
}
Already three days struggling to solve this problem so any help appreciated.
I have a simple component for check token from localStorage:
import Router from 'next/router';
const Blog = _ => {
const token = localStorage.getItem("token");
useEffect(_ => {
if(!token){
Router.push('/')
}
}, [])
}
This will work if we have a code like this:
<Link href="/blog">Blog</Link>
Then when you click blog you will be redirect to "/".
But if you type in browser url bar /blog and push enter you will not redirect to main page "/".
UPD:There is no token in localStorage
There are two problems with your code:
There is no return statement in the functional component. React throws an error if there is nothing returned.
If you type '/blog' in the browser, Nextjs throws an error, as the code is first run on the server( the server doesn't have a local storage - Error: localStorage is not defined). To resolve this you can do one of two things -
check whether the code is executing on the server or the client and then handle accordingly
move localStorage.getItem inside componentDidMount( or hooks equivalent).
import Router from "next/router";
import { useEffect } from "react";
const Blog = _ => {
useEffect(_ => {
const token = localStorage.getItem("token");
if (!token) {
Router.push("/");
}
}, []);
return <p>This is a blog</p>;
};
export default Blog;