frankcollins3 / Next-Water-App

Happy, Healthy Water Cycling App that tracks user/human fluid intake.
https://next-water-app.vercel.app
1 stars 0 forks source link

res not defined for server-side setCookie [10:16pm] #61

Open frankcollins3 opened 11 months ago

frankcollins3 commented 11 months ago

attempting to do: use JWT and cookies instead of localStorage to handle the persisting of logindata throughout the app.

error: in the setCookie() function there is no res

export function setCookie(res, name, value, options = {}) {
    const serializedCookie = cookie.serialize(name, value, options) // name, value, options
    res.setHeader('Set-Cookie', serializedCookie)
}

graphql/resolvers.ts:

    userLogin: async (parent, args) => {
    // userLogin: async (parent, args, {res}) => {
      const { email, password } = args
      try {
        const user:any = await new Promise((resolve, reject) => {
          passport.authenticate('local', { session: false }, (err, user, info) => {
            if (err || !user) {
              return reject(info ? new Error(info.message) : err);
            }
            resolve(user);
          })({ body: { email, password } });
        });
        // const SECRET_KEY = await JWTsecretKeyMaker()      
        // console.log("SECRET_KEY", SECRET_KEY)  
        const token = jwt.sign({ id: user.id }, 'water'); // Replace with your secret key for signing JWT
        // console.log('token from server', token)

        setCookie(res, 'token', token, {
          httpOnly: true,
          maxAge: 7 * 24 * 60 * 60, 
          path: '/',
        });
        // expiration date for cookie.

        return {
          id: user.id,
          googleId: user.google_id,
          icon: user.icon,
          username: user.username,
          password: user.password,
          email: user.email,
          age: user.age,
          token, // Include the token in the response
        };
      } catch (error) {
        console.log("error", error)
        throw new Error('An error occurred during login. Please try again.');
      }
    },

clientside invocation (which is currently just a test function)

const test = () => {
            console.log("testing!")

            axios
            .post('/api/graphql', {
            query: `
            query {
            userLogin(email: "tonyhawk@gmail.com", password: "birdman900" ) {      
                username,
                password,
                email,
                age,
                icon,
                token          
            }
            }
            `
            }).then( (data) => {
                console.log('data')
                console.log(data)
                console.log(data.data.data.userLogin)
                let loggedInUser:UsersLoginInterface = data.data.data.userLogin
                console.log('login-user', loggedInUser)
                let token:string = loggedInUser.token
                console.log('token')
                console.log(token)

                // setCookie = ('token', data.token, )
                setCookie('token', token, {
                    httpOnly: true,
                    maxAge: 7 * 24 * 60 * 60, // expiration date for cookie.
                    path: '/'
             })

            }).catch( (err) => {
                console.log('err')
                console.log(err)
            })
        }

also part of the problem is the click comes from an inline onClick function so won't have access to params like res from here { LOGIN_SIGNUP_BTN && <button onClick={test(res)}

these are the inline element-props errors returned by adding res parameter: Type 'void' is not assignable to type 'MouseEventHandler | undefined'.ts(2322) index.d.ts(1484, 9): The expected type comes from property 'onClick' which is declared here on type 'DetailedHTMLProps<ButtonHTMLAttributes, HTMLButtonElement>' (property) DOMAttributes.onClick?: MouseEventHandler | undefined No quick fixes available

Cannot find name 'res'.ts(2304) any

proposed approach: add the res object to the graphQL query params. res becomes undefined in the setCookie() function

0: first removed the res from the setCookie() function parameters which eliminates the setHeader() method from use setCookie(res, 'token', token, {

then chatGPT suggested this: to put the {res} into the (parent, args, {res}) which returns undefined. userLogin: async (parent, args, {res}) => {

frankcollins3 commented 11 months ago

proposed appropach: let res = args ? [10:23pm]

wrong in thinking: res is like data it's the object from which data is destructured or redeclared as var from object endpoint res.setHeader()

[10:27pm]

frankcollins3 commented 11 months ago

proposed approach: try another fetch method (possibly fetch() that isn't axios that gives access to the response. (which would be nuts if it works because chatGPT is trying everything with axios when it should look top-down at problem)

the problem is fixing the approach in that case not using axios and I only know this because chatGPT sent this:

When you make an HTTP request from the client-side using Axios, you are sending a request to the server, and the server processes that request and sends back a response. In the context of client-side code, you don't have direct access to the HTTP response object (res) that is used on the server-side.

However, even though you don't have access to the server's res object directly on the client-side, setting a cookie in the response is still handled by the server. When the server receives the request, processes it, and sends back a response, it can include the Set-Cookie header in the response to instruct the client to store a cookie.

Here's the flow of how it works:

The client (browser) sends an HTTP request to the server, containing the GraphQL query in your case.

The server processes the request, executes the GraphQL query, and prepares the response.

In your server-side resolver function (userLogin), after successful authentication, you generate a JWT token.

The server includes the token in the response object that it sends back to the client.

In your client-side code (the .then() block of Axios), you extract the token from the response data.

Using the setCookie function in your client-side code, you set the cookie in the browser's storage. The setCookie function will update the browser's storage (cookies) to include the token as specified in the Set-Cookie header in the server's response.

So, the setCookie function you are using in the client-side code handles the client-side part of setting the cookie in the browser's storage based on the token received from the server in the response data. The actual setting of the cookie in the client's browser is performed by the browser itself, not directly by your client-side code.

To summarize, the server sets the Set-Cookie header in the response, and the browser automatically handles setting the cookie based on that header when it receives the response.

[10:29pm]

frankcollins3 commented 11 months ago

solved with client side setting of cookie rather than server side [9:48am]