Tailored Pet Names Dev Journal Part 2: Next-Auth enters the "chat" (project)!
I played a tiny bit with authentication after work, but I'm too tired to dive in too deep.
It looks like i'll be using next-auth with this project
Twitter Post Link: twitter.com/Janetthedev/status/160512442306.. 12:54 AM · Dec 20, 2022
making SOME progress with authentication! So far its console.logging correctly, now the real fun begins
Twitter Post Link: twitter.com/Janetthedev/status/160617896393.. 10:44 PM · Dec 22, 2022
Users can now register for accounts!
Now to backtrack and get the sign in to work...
users
_id: ObjectId('6354345435')
name: "testingredirect"
email: "ttt @gmail .com"
password: "242423afafasfd3424"
image: "https: / / placekitten .com/250/250"
createdAt: 2022-12-23T09:05:55.892+00:00
updatedAt: 2022-12-23T09:05:55.892+00:00
__v: 0
Twitter Post Link: twitter.com/Janetthedev/status/160621687074.. 1:15 AM · Dec 23, 2022
welp login/session isn't working yet but made some progress today either way
Twitter Post Link: twitter.com/Janetthedev/status/160623515494.. 2:27 AM · Dec 23, 2022
slowly going through to figure out why the login/sessions is so stubborn 🤔
Confirmed react useForm is working right, so step 1 done
console showing:
Object {email: "test@ gmail .com, password: "testtest}
email: "test@ gmail .com"
password: "testtest"
Prototype: Object {....}
export default function LoginScreen(){
const {data: session} = useSession();
const router: useRouter();
const {redirect} = router.query;
useEffect(()=> {
if (session?.user){
router.push(redirect||'/');
}
}, [router, session, redirect]);
const {
handleSubmit,
register,
formState: {errors},
} = useForm();
const submitHandler = data => console.log(data)
...
}
Twitter Post Link: twitter.com/Janetthedev/status/160641277876.. 2:13 PM · Dec 23, 2022
It's been a struggle trying to get this app to work🙃 I got everything to work except the sessions won't authenticate for some reason?🤔 I've got a few things to try tomorrow otherwise I'll have to give in and ask on discord
console showing:
Object {error: null, status: 200, OK: true, url: "http: / /localhost:3000/api/auth/signin?csrf=true"}
email: kyu1312323@ gmail .com pass:testtest
session on login.js:[object Object]
Object {data: null, status: "unauthenticated"}
session on _app.js: "undefined"
Twitter Post Link: twitter.com/Janetthedev/status/160662308864.. 4:09 AM · Dec 24, 2022
its maddening since
new registrations show up in DB, errors properly show up if a user exists already in the database
if the incorrect login combo is given, they won't be redirected and the error messages work it's literally just the sessions!🙃😭
me @ the docs
Twitter Post Link: twitter.com/Janetthedev/status/160663420243.. 4:53 AM · Dec 24, 2022
I FIGURED IT OUT!! GUESS WHAT IT WAS?!
the next-auth version broke the app!! 12+ hours of pain and all i needed was "npm install next-auth@4.3.4"😭😂
Twitter Post Link: twitter.com/Janetthedev/status/160729108270.. 12:23 AM · Dec 26, 2022
I may now know more than any sane person needs to know about react-auth hahaha...ha
12+ hours later 🙃😂
Twitter Post Link: twitter.com/Janetthedev/status/160729736058.. 12:48 AM · Dec 26, 2022
also me explaining to my non-tech friends what a session is 😂
sessions are the powerhouse of the applications braincells! basically
"but uh, imagine a website is a doorman where you have to say the right password to get into the club
so you say "let me into the club" and you give the correct password.
The doorman's braincells are a session, he goes ah! You said the right password i'll let you in.
if the doormans braincells are dead, then you can shout the password to him and he'll just blink blankly at you"
Twitter Post Link: twitter.com/Janetthedev/status/160729798595.. 12:51 AM · Dec 26, 2022
me @ myself when I have a ton of features I need to add to make it a MVP (minimally viable product) but...wanting to focus on the unnecessary features😂
Twitter Post Link: twitter.com/Janetthedev/status/160796053689.. 8:44 PM · Dec 27, 2022
alright self I'll stop trying to make it sortable (for now) 😢
so! right now I'm adding a feature where logged in users can save names they like
Twitter Post Link: twitter.com/Janetthedev/status/160796097361.. 8:45 PM · Dec 27, 2022
which sounds simple but its going to need many parts...
so first up! if they click on the checkbox and they're not signed in, show "you must be signed in to like names!"
Twitter Post Link: twitter.com/Janetthedev/status/160796324216.. 8:54 PM · Dec 27, 2022
progress! If you're not signed in, the react-toastify alert will appear.
Buuut when you're signed in, if you click a heart icon, it will change them ALL red 🤔
which makes sense, as I told all the icons to get their color from "likesColor"
/ / ############# LIKES FEATURE ##########/ /
const [nameLiked, setNameLiked]=useState(false)
let likesColor= nameLiked? "red":"grey"
const handleLikes = (e) => {
{(status==="authenticated")?
setNameLiked(!nameLiked):
toast.error("you must be signed in to use this feature")
}
};
tagFilters.every((tag)=>
name.tags.includes(tag)&&
<tr key={name._id}>
<td className="text-purple-200 border-b-2 border-amber-300 px-4 py-2 text-left font-black">
<label>
<input
style={{display:"none"}}
type="checkbox"
checked={nameLiked}
onChange={handleLikes}
data-name-id={name._id}
/ / data-amount-of-likes={names.likedby.length}
/>
<fontAwesomeIcon
icon={faHeart}
className="text-4xl"
color={likesColor}/>
{name.name.length}
</label>
</td>
......
)
Twitter Post Link: twitter.com/Janetthedev/status/160797753954.. 9:51 PM · Dec 27, 2022
Welp here I am again 😂
I need to get session.user._id to be usable in the return section of my next js's react component but alas I can't get it to work
Tried useEffect, async await and a few others things but no luck 🙃
Twitter Post Link: twitter.com/Janetthedev/status/160806409734.. 3:35 AM · Dec 28, 2022
its not pretty but it works! annnd its 6am 😂
export default function Example ({category, nameList, pageProps}){
const {data: session, status} = useSession()
let [userId, setUserId]=useState()
useEffect(()=> {
const UserId=localStorage.getItem("session")
console.log(userId);
setUserId(userId)
},[])
.......
}
Twitter Post Link: twitter.com/Janetthedev/status/160809867645.. 5:52 AM · Dec 28, 2022
I laughed at myself today, I was wondering why some nav buttons always worked and others were always questionable?
Turns out for some buttons I had linked TO the text, not the button itself😂whoops! Yeah that'd def cause problems haha
<Menu as "div" className="inline-block text-left">
<Menu.button className="inline-flex px-4 py-2 text-sm font-medium text-white
border-r-4 border r-violet-400
hover:bg-opacity-30 hover:border-b-4 border-b-yellow-400
focus:outline-none focus-visible:ring-2
focus-visible:ring-white focus-visible:ring-opacity-75">
<FontAwesomeIcon icon={faIgloo} className="text-xl mr-1 text-violet-100"/> <====this should be in the Link too
<Link href="/"> / /
<a> Home </a>
</Link>
<Menu.Button>
</Menu>
Twitter Post Link: twitter.com/Janetthedev/status/160952193930.. 4:08 AM · Jan 1, 2023
Today started like this, and ended like this!
I'm curious if anyone will remember what my avatar is from 👀 wink wink nudge nudge. Nothing like starting of the year with a dad joke😉
Twitter Post Link: twitter.com/Janetthedev/status/160952435837.. 4:18 AM · Jan 1, 2023
You gotta love simple fixes!
I noticed the grey space under some areas, so I simply set the height to the screen height. Fixed! 🎊
return (
<div className="bg-violet-900 h-screen"> <==h-screen here
<Layout> </Layout>
.....
)
Twitter Post Link: twitter.com/Janetthedev/status/160982641775.. 12:18 AM · Jan 2, 2023
I added a toast notification for when someone successfully and unsuccessfully adds a name
Twitter Post Link: twitter.com/Janetthedev/status/160983503497.. 12:52 AM · Jan 2, 2023
The biggest issue I'm facing is to be able to access the session.user._id, so i can use the unique _id for mongoDb queries
Next Auth's getSession() only works on the CLIENT side NOT server side. so the session data can't be used to talk to mongoDB ☹️ unless I say AWAIT getSession()
Twitter Post Link: twitter.com/Janetthedev/status/160985784041.. 2:23 AM · Jan 2, 2023
I currently save the current user's id in localStorage but this is ALSO only client side (and security wise, isn't a good option)
I thought over my options, and the best choice seems to be to use contextAPI and getSession (store user id so it can be used throughout the app)
export default function LoginScreen(){
/ / grab data from useSession and rename data to session
const {data: session} = useSession();
const router: useRouter();
const {redirect} = router.query;
/ / extract redirect from router.query
/ / import this from line 2/react
useEffect(()=>{
if(session?.user){
localStorage.setItem("session",JSON.stringify(session.user._id))
/ / console.log(session.user._id),
router.push(redirect || '/');
}
}, [router, session, redirect]);
/ / if the session exists, then the user is already signed in. so if this is true, go back to the homepage
/ / we need to use router (line 8) to redirect our user
}
My Options:
When logging in, use the contextAPI with getSession() to save session in a stored state
when logging out, remove session from stored state
con: will have to use await to access session data when first adding it to the context api
pro: won't have to use unstable_getServerSession
use unstable_getServerSession with ContextAPI
Pro: won't need to use await to access session data like we would with getSession() since this is server side not client side
con: unstable, aka its experimental and may be removed one day
use unstable_getServerSession by itself
con: will have to call it every time its used
con: unstable aka its experimental and may be removed one day
pro: won't have to set up contextAPi
Twitter Post Link: twitter.com/Janetthedev/status/160985893514.. 2:27 AM · Jan 2, 2023
so when the user logins in, I'll have it set up so that it saves the current user's Id in the context (storage for global state objects)
When they sign out, it'll be removed from context
Twitter Post Link: twitter.com/Janetthedev/status/160985949925.. 2:29 AM · Jan 2, 2023
So far I know:
- Context object STORES the shared data
- Provider DELIVERS the context object when requested
Creating the actual context itself seems dead simple! 🥳
But I can feel my brain go numb whenever I try to figure out how to write the provider bit 🥴
import React, {useContext, createContext, useState, useEffect} from 'react'
/ / create context
const UserSessionContext= createContext(null)
/ / https:/ / www. youtube .com/watch?v=t9WmZFnE6Hg&ab_channel=PedroTech
/ / 6:53 null is good for testing
Twitter Post Link: twitter.com/Janetthedev/status/160986295913.. 2:43 AM · Jan 2, 2023
huh it seems I misunderstood the context API. It looks like you have to declare the prop when you wrap something in < context . provider> . And my _app.js page doesn't have access to session, only its children... so I can't place session in the context store?
import UserSessionContext from '../src/context/UserSessionContext';
function MyApp({
component,
pageProps: { session, ...pageProps}
})
{
/ / setting up the prop for UserSessionContext, grabbing session information
/ / ????
return (
<SessionProvider session={session}>
{/* <UserSessionContext.Provider value={sessionInfo}>
Every context Object comes with a Provider React component
The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider,
in this case ALL components */}
<Component {...pageProps}/>
{/* </UserSessionContext.Provider> */}
.......
)
}
_app.js
import React, {useContext, creatContext, useState, useEffect} from 'react'
/ / create context
const UserSessionContext=createContext(null)
Twitter Post Link: twitter.com/Janetthedev/status/160989616357.. 4:55 AM · Jan 2, 2023
hoping someone will see my question on the 100devs discord, looks like I might have to use Next auth's unstable_getServerSession after all? 🥴
What I submitted:
hi everyone, I need some advice for my next.js project which uses Next auth for authentication.
The main problem is that I'm trying to figure out the best way to grab the current user's id from the current session so its available immediately server side. This way I can use it to query my mongoDB database.
Follow up comment from me:
My thought process:
So I understand getSession() is client side only, so it would have to wrapped in an await to grab session data. Otherwise it would return null.
So what is the best way to make it so session data is available RIGHT AWAY, server side, so I can use the current user_id when sending queries to the MongoDb database?
(my [ ... nextAuth].js is set up so that user_id is included in the returned session object. My session strategy is JWT) github.com/JSMarsh813/PetProfileTailor/blob..
For example, on my dashboard page I want to grab the user's id from the current session and then query my mongodb database, so I can grab the users most current information. I would then use that information to fill out the dashboard page (user's likes, user's profile image, user's username, ect).
Another Example, my app gives users a list of names they can like or dislike. I want to grab the userID to query the MongoDB database to see if the current user already liked a name. And then sent a get or patch request when the user likes or dislikes the name.
I thought about using react context in _app.js but I believe session isn't available in _app.js? Aka only its child components have access to session, so theres no way to set the current session prop for the userSessionContext right?
use unstable_getServerSession, though I'd rather not center a large part of my app on an experimental feature that could be removed if possible. next-auth.js.org/tutorials/securing-pages-a..
Some other method?
jmfurlott.com/handling-user-session-react-c.. I had found this, would you all say js cookies with context is a good option to grab user ids?
Twitter Post Link: twitter.com/Janetthedev/status/160989673160.. 4:57 AM · Jan 2, 2023
Yeah as I figured, I can't access useSession in _app .js, since _app .js can't be wrapped in a
<SessionProvider session={session}>
😭 Still tried anyway for the wild thrill of trying impossible things haha
But I confirmed that I got context to work with a normal string :)
Twitter Post Link: twitter.com/Janetthedev/status/160990293070.. 5:22 AM · Jan 2, 2023
Its times like these that I really LOVE💓 react!
Look at that, ONE beautiful line which secretly carries two reusable components
MainChartComponent=54 lines and
nameListing which is inside MainChartComponent = 70ish lines
🥰🥰🥰
<section className="favoriteNames">
<h4> Your Favorite Names </h4>
<MainChartComponent nameList={nameList}/>
</section>
Twitter Post Link: twitter.com/Janetthedev/status/160991342193.. 6:04 AM · Jan 2, 2023
Small achievement! 🎊
Fixed the tags so when they show up there's a ", " between them 😁
Laughed when I tried to do ".split().Join(", ")" before my brain clicked on. Braincell: "aayy this is an array not a string friend :)
"
<td className="border-b-2 border-amber-100 px-4 py-2 text-left fond-medium">{
(name.tags)
.map(names=>names)
.join(", ")}
</td>
Twitter Post Link: twitter.com/Janetthedev/status/160991687005.. 6:17 AM · Jan 2, 2023
Success is mine! I could cry with joy and relief 🥺The put request for my likes features finally works!
I've been slooowly working on it with any spare time I've had this week, and it finally paid off 🔥
Twitter Post Link: twitter.com/Janetthedev/status/161134921478.. 5:09 AM · Jan 6, 2023
For a sec I couldn't figure out why I couldn't get my mobile menu's text to center 🤔
I had forgotten they were flexed, once that was removed it works!
<Menu.Item as="div">
<Link href="/adddescriptions">
<button
classname="hover:bg-yellow-500
hover:text-violet-900
text-white w-full items-centered
group flex <===where the issue was
"
......
Twitter Post Link: twitter.com/Janetthedev/status/161172862210.. 6:17 AM · Jan 7, 2023
I was getting this error that what rendered was different than what the server had initially rendered
I realized it was because the tagList from the fetch only was grabbed AFTER the server had rendered the page.
Once I told it to wait, no more error messages ~
export const getServerSideProps = async () => {
let tagList= await fetch('http : / / localhost:3000 /api/individualTags');
let categoryList= await fetch ('http : / / localhost:3000 /api/name-categories');
let tagData= await tagList.json()
let categoryData = await categoryList.json()
return {
props: {
tagList: tagData, <=== highlighted code
categoryList: categoryData
},
}
/ / and provide the data as props to the page by returning an object from the function
}
function AddNewNameWithTags({tagList, ccategoryList}){
const {data: session, status} = useSession()
console.log(status)
console.log(session)
return (
<div className="bg-violet-900 h-screen text-white">
<Layout> </Layout>
<div style={{width:"700px"}} className="mx-auto mt-4">
{/* if not signed in, do not allow them to add names*/}
{(status!="authenticated")&&<div> To avoid spam, we ask users to sign in to add names </div>}
{(status === "authenticated") &&
<p> Signed in as {session .user .name} </p>}
<NewNamesWithTagData tagList={tagList}/>
.....
)
}
Error Message in console:
Warning: Prop
id
did not match. Server: "react-select-14-live-region" client"react-select-3-live=region"span
withEmotionCache/<@webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-6a8883da9.browser.esm.js::57-66
AllyText
LiveRegioin@webpack-internal:///./node_modules/react-select/dist/Select-40119e12.esm.js:122:23
div
.....
{(status === "aunthenticated") &&
<p> Signed in as {session .user .name}</p>&&
<NewNameWithTagsData tagList={tagList} userId={session.user._id}/>}
Twitter Post Link: twitter.com/Janetthedev/status/161194549372.. 8:38 PM · Jan 7, 2023
the user who submits the new names id is now added to the name in the database! (I was having problems but then remembered getSession() has to be used on pages not components, so I passed the session as a prop)
Descriptions can now be added as well
Twitter Post Link: twitter.com/Janetthedev/status/161199445343.. 11:53 PM · Jan 7, 2023
Is anyone familiar with next Auth sessions for next js? I'm trying to add the profile image data to my session and I can't get it to work🤔
Below is my nextauth file, console.log, mongodb data and user model #SoftwareDeveloper #Nextjs #nextauth
What the console showed:
Object {user: {...}, expires: "2023-02-10T14:45:56.120Z"}
expires: "2023-02-10T14:45:56.120Z"
user: Object {name: GhibliMagic", email: "teessssst@ gmail .com", _id:"22222222222sfds"}
_id:"22222222222sfds"
email: "teessssst@ gmail .com"
name: "GhibliMagic"
<prototype>: Object {...}
....
Atlas MongoDB Database
_id: "22222222222sfds"
name: "GhibliMagic"
password: "$325345^%654$%^*&*7876898fasfcsf3433"
createdAt: 2022-12-26T02:51:26.328+00.00
updatedAt: 2023-01-05T14:36:11.922+00.00
__v: 1
favbehaviors: Array
favnames: Array
profileimage: "http : / / placekitten. com/50/50"
ShelterNext>models>user.js>UserSchema
const mongoose = require("mongoose")
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: false,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
faveNames: {
type: Array,
default: []
},
favBehaviors:{
type: Array,
default: [],
},
profileImage:{
type:String,
default:"http : / / placekitten .com/50/50"
}
}, {timeStamps:true})
const User= mongoose.Models.User || mongoose.model('User', UserSchema);
export default User;
Twitter Post Link: twitter.com/Janetthedev/status/161320104647.. 7:47 AM · Jan 11, 2023
tried this and it didn't work either :(
[...nextAuth].js
provider:[
......
if (user && bcrypt.js.compareSync(credentials.password, user.password)){
const returnedUser= {
_id: user ._id,
name: user .name,
email: user .email,
profileimage: user .profileimage,
}
return Promise.resolve(returnedUser)
}
throw new Error ('Invallid email or password');
......
]
Twitter Post Link: twitter.com/Janetthedev/status/161320159292.. 7:50 AM · Jan 11, 2023
REPLY FROM Rawand Faraidun @rawandfaraidun twitter.com/rawandfaraidun
try replacing the
callbacks
object with this:callbacks: {
jwt({ token, user }) {
if (user) token = user
return token
},
session({ session, user, token }) {
session.user = token
return session
}
}
Twitter Post Link: twitter.com/rawandfaraidun/status/161398998.. 12:02 PM · Jan 13, 2023
THANK YOU! That was it, words can't express my gratitude!
You're a lifesaver
Twitter Post Link: twitter.com/Janetthedev/status/161420041810.. 1:59 AM · Jan 14, 2023
alright so on postman my api, which gives a list of all names the current user liked works, but I'm still trying to get it to work in the actual app...
Twitter Post Link: twitter.com/Janetthedev/status/161382075713.. 12:50 AM · Jan 13, 2023
Got it to work! On the dashboard, now only the current user's favorite names show up!🥳
export const getServerSideProps = async (context) -> {
.....
let filteredNames=""
if (session){
let filteringNames= await fetch(`http : / / localhost: 3000/api/individualnames/namesContainingUserId/${session.user._id}`);
filterednames = await filteringNames.json
}
}
Twitter Post Link: twitter.com/Janetthedev/status/161383648735.. 1:52 AM · Jan 13, 2023
Thanks to @rawandfaraidun (twitter.com/rawandfaraidun) I managed to fix my [...nextauth].js file so the session object will have the user's profile image link!
now when I load session in getServerSideProps with unstable_getServerSession, I can grab the profile image before rendering even starts 🥳
export const getServerSideProps = async (context) =>{
let response= await fetch('http : / / localhost: 3000/api/name-categories');
let data = await response.json()
let nameResponse = await fetch('http : / / localhost: 3000/api/individualNames');
let nameData = await nameResponse.json()
const session = await unstable_getServerSession(context.req, context.res, authOptions) <=== highlighted code
}
Twitter Post Link: twitter.com/Janetthedev/status/161423403204.. 4:12 AM · Jan 14, 2023