Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forwarding client's cookies to API when calling from on server #37

Closed
asadm opened this issue Apr 5, 2016 · 16 comments
Closed

Forwarding client's cookies to API when calling from on server #37

asadm opened this issue Apr 5, 2016 · 16 comments

Comments

@asadm
Copy link

asadm commented Apr 5, 2016

Sorry if this is a noob question. What happens when the API call needs user's session. I assume those session cookies won't be forwarded to the API endpoint when the rendering happens on server-side?

Any idea on how should I forward user's cookies to the API endpoint. I think it will be somewhere inside HttpClient.js?

Thanks

@omnidan
Copy link

omnidan commented Apr 6, 2016

@asadm it should be sending the cookies automatically (if you're doing a cross request make sure to add .withCredentials()), but the problem I'm having with this is that it doesn't work on the server side. I keep getting Error: Failed to serialize user into session when the server sends a login request. In the browser or with curl, the login request works fine, though.

@jaredpalmer
Copy link
Owner

Feel free to send a PR with axios or fetch etc.

@omnidan
Copy link

omnidan commented Apr 6, 2016

@jaredpalmer I haven't figured out how to solve the problem yet, but I can try to work on a PR once it's fixed. 😅

@omnidan
Copy link

omnidan commented Apr 6, 2016

I'm getting the same error with fetch, by the way.

@jaredpalmer
Copy link
Owner

@omnidan
Copy link

omnidan commented Apr 6, 2016

@jaredpalmer Sadly, not at all. This has to do with universal rendering, passport works fine. It also works fine to send requests from the browser or curl, just when the server in this boilerplate makes the request to get the initialState, it fails. I assume this is because the server-side doesn't store the user session. Is there any way to do this?

@omnidan
Copy link

omnidan commented Apr 6, 2016

I think the easiest way to work around this issue is to return a token and store that in the state, then later authenticate requests with the token. Would be nice if client/server shared the correct user session automatically, though 😄

@omnidan
Copy link

omnidan commented Apr 6, 2016

This might be a related issue: http://stackoverflow.com/a/12735003/702288

@jaredpalmer
Copy link
Owner

can you link to an example repo? also are you using express-session?

@omnidan
Copy link

omnidan commented Apr 6, 2016

@jaredpalmer Unfortunately I can't share the code, but it's not hard to add passport to your existing boilerplate: http://passportjs.org/docs

Yes I am using express-session. I have tried using superagent.agent(), but it didn't solve the issue.

@omnidan
Copy link

omnidan commented Apr 6, 2016

@jaredpalmer I just cloned a fresh instance of your boilerplate and added express-session. Setting req.session crashes it (I did in src/server/api/posts.js). You can check this out in my fork omnidan/react-production-starter (relevant commit).

@omnidan
Copy link

omnidan commented Apr 6, 2016

Ok, nevermind my issue seems to have been unrelated to this 😊

I just found out that it couldn't serialize the user because the data was sent via json from the server, but urlencoded from the browser/curl. adding app.use(bodyParser.json()) to my server fixed the issue for me.

@omnidan
Copy link

omnidan commented Apr 6, 2016

I still have the problem that the session doesn't seem to work correctly. I changed one request to be (for testing purposes):

callAPI: () => http.post('http://localhost:3003/login', {
      email: 'test@test.com',
      password: 'test'
    }).then(data => {
      console.log('login', data)
      return http.get('http://localhost:3003/user')
        .then(data => console.log('user data:', data))
    }),

The output of this is:

login { email: 'test@test.com' }
user data: { error: 'Not authenticated, please log in.' }

If I do the /login request and then access /user in the browser, it works fine. Seems like the server isn't sharing sessions with the client properly.

@asadm
Copy link
Author

asadm commented Apr 6, 2016

I kinda solved it this way:
When user requests the page from express server. The req holds any session cookies in it's header. I just forward req.headers.cookie down till HttpClient.js:

get: (cookies, path) => new Promise((resolve, reject) => {
    request
      .get(getUrl(path))
      .accept('application/json')
      .set("Cookie",cookies)
      .end((err, res) => {
        if (err) {
          if (err.status === 404) {
            resolve(null);
          } else {
            reject(err);
          }
        } else {
          resolve(res.body);
        }
      });
  }),

Does this make sense?

@omnidan
Copy link

omnidan commented Apr 6, 2016

@asadm good idea! I was gonna solve this by storing a login token in the redux store, but this is pretty much the same concept using cookies. I'll try this out in a bit 😁

@rowellx68
Copy link
Contributor

@omnidan I have done this approach and it's pretty similar to the one @asadm provided.

  getWithToken: (path, token) => new Promise((resolve, reject) => {
    request
      .get(getUrl(path))
      .set('X-User-Token', token)
      .accept('application/json')
      .end((err, res) => {
        if (err) {
          reject(err);
        } else {
          resolve(res.body);
        }
      });
  })

@jaredpalmer jaredpalmer mentioned this issue Jun 9, 2016
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants