when a user successfully logs in, isn't the `sessi...
# general
j
when a user successfully logs in, isn't the
session
of the
useSession
hook (from
@ory/elements-react/client
) supposed to update with the user's session when we have a successful login from e.g.
ory.verifyLoginOtp
(from
@ory/client-fetch
)? is the intent that we use
refetch
manually? for some reason, we have a weird bug in prod where refetch gets called in an infinite loop and we're not sure whether it's something in our code or something internal to ory
b
Could you show the code you're observing this with? It could very well be an issue with the
useSession
hook, though. The hook is pretty bare bones at the moment, and will likely need a few improvements to work in all cases. But at the moment, the hook doesn't automatically refetch if something in the session changes, because it can't possibly know if something changed. We could implement a polling mechanism, or time based staleness, but that will also never be as accurate as refetching manually.
j
Ah, I assumed the ory calls would just internally refetch; I take it I can make whatever ory call the refetch method makes in my non-component code to update it though, right? Will send some example code shortly but we've since fixed the infinite refetch (which was a problem with our code) and now we have an issue that is certainly ory-specific (likely our own misuse, but still something we'd love some more-knowledgeable eyes on). Locally, the session is defined after we
refetch
post-login, but in deployed environments, despite the refetch happening and a successful whoami network request, the session variable is not defined; when the page is refreshed, however, the session variable is defined correctly, which leads me to think it might be a hydration issue or a race condition with the instantiation of ory.
Okay I believe I've figured out the underlying issue -- for some reason, some of our
whoami
requests are being rejected with a 401 (I looked at the CSRF page here https://www.ory.sh/docs/troubleshooting/csrf but that didn't help; the cookies seem to be being sent in the headers so I assume it's a cors issue?). Specifically, on localhost, a call to
/sessions/whoami
is being made (no idea why that url is being used in the first place instead of
<http://localhost:3000/api/.ory/sessions/whoami>
, nor do I understand how it's actually succeeding unless it's via the middleware) and succeeding, but in prod, requests are being made to our custom domain in ory (
<https://auth-staging.example.com>
) and failing with "No valid session credentials found in the request." We've set
ORY_SDK_URL
and
NEXT_PUBLIC_ORY_SDK_URL
to the project url locally (
<https://whatever-whatever.projects.oryapis.com>
) and, in our deployed environment, they're both set to
<https://auth-staging.example.com>
, yet locally it always uses localhost but when deployed it uses two different urls for the various requests. I've put some relevant code below, along with the problematic request and our settings in ory console. Note that our app is at
<http://staging.example.com|staging.example.com>
and our ory custom domain is
<http://auth-staging.example.com|auth-staging.example.com>
, where
<http://example.com|example.com>
is our domain and the same between both. Ory console settings for custom domain
Copy code
Domain	Status	CORS Enabled	CORS Allowed Origins	
<http://auth-staging.example.com|auth-staging.example.com>
Cookie Domain: <http://example.com|example.com>
Active	Enabled	<https://auth-staging.example.com>, <https://staging.example.com>
getOry.ts
Copy code
import { Configuration, FrontendApi } from '@ory/client-fetch';
import { edgeConfig } from '@ory/integrations/next';

let oryInstance: FrontendApi | null = null;

/**
 * Returns a singleton instance of the Ory Frontend API client
 */
const getOry = (): FrontendApi => {
  if (!oryInstance) {
    oryInstance = new FrontendApi(
      new Configuration({
        ...edgeConfig,
        headers: {
          Accept: 'application/json',
        },
      }),
    );
  }

  return oryInstance;
};

export { getOry };
middleware.ts
Copy code
import type { OryConfig } from '@ory/nextjs';
import { createOryMiddleware } from '@ory/nextjs/middleware';

if (!process.env.NEXT_PUBLIC_ORY_JWT_TEMPLATE) {
  throw new Error(
    'NEXT_PUBLIC_ORY_JWT_TEMPLATE environment variable is required',
  );
}

const oryConfig: OryConfig = {
  override: {
    applicationName: 'Sway',
    loginUiPath: '/login',
    registrationUiPath: '/login',
    defaultRedirectUri: '/',
  },
};

const middleware = createOryMiddleware(oryConfig);

export const config = {
  matcher: [
    '/((?!_next/static|_next/image|public/assets|sitemap.xml|robots.txt).*)',
  ],
  runtime: 'nodejs', // Explicitly use nodejs runtime instead of edge
};

export { middleware };
layout.tsx
Copy code
...
import { SessionProvider } from '@ory/elements-react/client';
import { getServerSession } from '@ory/nextjs/app';
...
const RootLayout = async ({ children }: RootLayoutProps) => {
  const session = await getServerSession();
  ...
          <SessionProvider session={session}>
            ...
                    {children}
            ...
          </SessionProvider>
  ...
}

export default RootLayout;
problematic request, copied as curl from devtools
Copy code
curl '<https://auth-staging.example.com/sessions/whoami>' \
  -H 'accept: application/json' \
  -H 'accept-language: en-US,en;q=0.9' \
  -b '__cflb=04dTodMRLj6awUFAsKnYEzjSxUSGGpDriZF7v1vKfH; _cfuvid=OFjW4fSh65FjlZFuPbh6w0oCe.7y4fxSQXYRJ.jLM1A-1744604714983-0.0.1.1-604800000; __cf_bm=JTkmcJdRoDrKEIUbrVlA2EdFxW5NyXl7.CFBgw4lKmE-1744606677-1.0.1.1-AN4.0UJZ4A2hJt9hEOANR7ffyh4PU3ubUdFtJA4O9Nr3f.L.S_0q3hOoeTb63jbyKlb9XZ2nt1K596q37Kcv.pfQNF7kiWe5B2wKOapzIFY' \
  -H 'origin: <https://staging.example.com>' \
  -H 'priority: u=1, i' \
  -H 'referer: <https://staging.example.com/>' \
  -H 'sec-ch-ua: *******' \
  -H 'sec-ch-ua-mobile: *******' \
  -H 'sec-ch-ua-platform: *******' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: same-site' \
  -H 'user-agent: *******'
response to that request
Copy code
{
  "error": {
    "code": 401,
    "status": "Unauthorized",
    "request": "15c6c6c6-0616-9ee2-be29-8b3b78c48387",
    "reason": "No valid session credentials found in the request.",
    "message": "The request could not be authorized"
  }
}
Well this might not be the intended solution, but at this point I'm so excited it works I don't much care: setting
NEXT_PUBLIC_ORY_SDK_URL=<https://staging.example.com/api/.ory>
actually routes everything correctly
b
No, setting the env var is the intended solution, but it's not really cleaned up yet. Thanks for the feedback.
j
Okay even more bizarrely, when I set
NEXT_PUBLIC_ORY_SDK_URL=<http://localhost:3000/api/.ory>
locally, instead of actually changing the url of the
whoami
requests (like it does in our deployed staging environment), it instead just causes the
whoami
requests to fail (in the way I expected, where they 404 because we don't have a
/sessions
route and it's trying to get
localhost:3000/sessions/whoami
). What's the point of all the CORS stuff in the custom domain settings if not to allow these requests to go to our ory url instead of being proxied? I'm not saying this snarkily, I actually don't understand what these settings are for 🙂 And this page says we don't need the api route at all, but maybe that's outdated? https://www.ory.sh/docs/getting-started/integrate-auth/nextjs#go-to-production
b
The guide is indeed outdated, we're working on it. Apologies for that. The Next.js middleware causes requests to the Ory APIs to be proxied locally, so that you don't need to configure CORS for local development. CORS can still be configured for other local envs (where the middleware isn't available), or for environments on different domains, though in that case you quickly run into cookie issues as well (e.g. if you're talking to the Ory APIs from an entirely different root domain).
I am not sure I understand, why the requests locally would fail, though.
localhost:3000/sessions/whoami
should be handled by the Next.js middleware, and proxy the request to the Ory APIs.
j
All good I'm aware that I'm on the bleeding edge here and expecting docs to not match fully 🙂 I just want to make sure I'm not doing things insecurely!
Alrighty, well in that case we'll just leave the env vars as they work in both environments and I can call this out when I eventually make a self-contained example repo for all of this so you can test it out yourself! Thanks again for all the help I really appreciate it.