ory / sdk

The place where ORY's SDKs are being auto-generated
Apache License 2.0
139 stars 86 forks source link

Do not make a request for each public user #246

Closed hyperknot closed 6 months ago

hyperknot commented 1 year ago

Preflight checklist

Describe your problem

A typical website might have millions of daily public visitors while having just a few active logged-in users.

Currently, the FrontendApi.toSession() makes a request (which is actually 2 requests) every single time it is called. In all the code examples I could find on GitHub, toSession() is simply placed at the top of index.tsx or similar page of the app, meaning that by default we send a request for every single visitor to the auth server.

Some apps might even await on toSession(), which is just very bad for UX.

Describe your ideal solution

There is absolutely no point in sending a request for the non-logged-in users to the auth server. We should just check if a cookie exists and if it does not, then we should just terminate early.

Workarounds or alternatives

AFAIK, there is only 2 ways to do this currently:

I think the 2 cookie solution would be the best for performance and UX.

Version

@ory/kratos-client 0.11.0 (but same with client 1.x)

Additional Context

No response

hyperknot commented 1 year ago

A PoC would be:

import Cookies from 'js-cookie'

// upon successful login:
Cookies.set('logged_in', '1', { expires: 3650 }) // 10 years

// in init function
if (!Cookies.get('logged_in')) {
  return
}

try {
  const { data } = await this.ory.toSession()
  this.setSession(data)
} catch (e) {}

This is currently only possible if the app handles the login flow. To make it work universally, Kratos would need to add the logged_in cookie with HttpOnly = false, then it'd be much simpler in the client side.

Ideally this should be totally transparent for the user, hidden behind toSession().

aeneasr commented 1 year ago

Hey, that's a great point :) Please note that this won't work client-side as the client has no way of knowing whether the cookie exists (beacuse it is httpOnly).

We want to provide better high-level SDKs that wrap the basic autogenerated SDK we have here.

We are also working on deploying a system that significantly improves requests latencies, bringing them down to ~25-30ms for unauthenticated requests

hyperknot commented 1 year ago

I implemented this by modifying the Next.js integration API.

Changing this:

          res.headers["set-cookie"] = parse(res)
            .map((cookie) => ({
              ...cookie,
              domain,
              secure,
              encode,
            }))
            .map(({ value, name, ...options }) =>
              serialize(name, value, options as CookieSerializeOptions),
            )

into this:

          const cookiesParsed = parse(res)
          const cookiesMod = cookiesParsed.map(cookie => ({
              ...cookie,
              domain,
              secure,
              encode,
          }))

          const sessionCookie = cookiesMod.filter(c => c.name === 'ory_kratos_session')[0]
          if (sessionCookie) {
            cookiesMod.push({ ...sessionCookie, name: 'login', value: '1', httpOnly: false })
          }

          const cookiesSerialized = cookiesMod.map(({ value, name, ...options }) =>
            serialize(name, value, options as CookieSerializeOptions)
          )
          res.headers['set-cookie'] = cookiesSerialized

It's just the added cookiesMod.push({ ...sessionCookie, name: 'login', value: '1', httpOnly: false }) basically. Everything is copied from the session cookie, except name, value and httpOnly.

github-actions[bot] commented 7 months ago

Hello contributors!

I am marking this issue as stale as it has not received any engagement from the community or maintainers for a year. That does not imply that the issue has no merit! If you feel strongly about this issue

Throughout its lifetime, Ory has received over 10.000 issues and PRs. To sustain that growth, we need to prioritize and focus on issues that are important to the community. A good indication of importance, and thus priority, is activity on a topic.

Unfortunately, burnout has become a topic of concern amongst open-source projects.

It can lead to severe personal and health issues as well as opening catastrophic attack vectors.

The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone.

If this issue was marked as stale erroneously you can exempt it by adding the backlog label, assigning someone, or setting a milestone for it.

Thank you for your understanding and to anyone who participated in the conversation! And as written above, please do participate in the conversation if this topic is important to you!

Thank you 🙏✌️