I have an API built with Laravel and Sanctum.
Front-end is built in NextJS. CORS and communication is doing fine - apparently, I can't see errors even with POST requests.
Login goes fine, Laravel sets a cookie for .mydomain.com
, path "/", and it's HTTP Only. Nice. No errors in the console. I can see the cookie in the chrome dev tools with the JWT from Laravel Sanctum.
Ok, so after submit the Login form and receive the success response with the jwt
cookie/token, the user is redirected to the home page. In NextJS Home page, I have a function to check if the session still valid in Laravel API. This function run inside getServerSideProps
hook, a.k.a. NodeJS.
To do that, a POST request is made from NextJS server (NodeJS) to Laravel API, trying to get information about the user. In this request, the cookies are "forwarded" to Laravel. But here is the strange thing: the request never gets to Laravel. It is "hitting" NextJS API routes instead. And, of course, the route doesn't exist in Next. It should request Laravel API.
So, step by step:
- User types
mydomain.com/login
and gets the Login page from NextJS. - User fulfills and submits the form. React (client-side) calls Laravel using Axios at
api.mydomain.com/api/login
. - Laravel API validates the form and sets a
jwt
cookie in the response having:
3.1) HTTP Only
3.2) Path: `/`
3.3) Domain: `.mydomain.com` (accordingly to `RFC 6265`
3.4) Value: the JWT token from Laravel Sanctum
After React gets the login response with the
jwt
cookie, React code redirects the user tomydomain.com/
(root URL). Here is the beginning of the problem.NextJS will run/build the homepage on server-side. During the SSR in NextJS, the Homepage makes use of
getServerSideProps
hook in NextJS, and it tries to callapi.mydomain.com/api/me
to validate the session/cookie/jwt. But, for an unknown reason, it actually callsmydomain.com/api/me
. Note that my API runs at the subdomainapi.mydomain.com
and NextJS atmydomain.com
.
It looks like Axios is 'ignoring' the baseURL
config. But I even replaced the relative URL with the absolute path, hardcoded, subdomain. Still see the same error. First, it was resulting in a 404 page - because NextJS doesn't have a /pages/api/me.ts
file. It took me a giant time to think: "Hey, maybe this request is going to NextJS itself and not Laravel API". So, I put in NextJS a file that outputs the following sentence:
EERRRROOORRRRRR!!!! THIS SHOULD NEVER BE CALLED, SINCE LARAVEL SHOULD ANSWER THIS CALL, NOT NEXTJS API!!!!!
and I could see this response in the logs. Here is my HTTP method:
export async function me(headers: Headers = {}): Promise<User> {
try {
const config = {
baseURL: 'api.mydomain.com/api',
withCredentials: true,
headers: {
...headers,
},
};
console.log('config', config);
// I was using a global configured instance, but now I'm creating a new one here:
const tempAxios = axios.create(config);
console.log('call HTTP me(). Config:', config);
// the "space" between // and api is only because Stackoverflow blocks URL in the post
const { data } = await tempAxios.get('https:// api.mydomain.com/api/user');
return Promise.resolve(data);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error('call HTTP me() ERROR', error.config);
return Promise.reject(error);
}
}
Then, I can see in NextJS / Node logs:
[app-frontend] [2022-03-03 23:39:12] call HTTP me(). Config: {
[app-frontend] [2022-03-03 23:39:12] baseURL: 'api.mydomain.com/api',
[app-frontend] [2022-03-03 23:39:12] withCredentials: true,
[app-frontend] [2022-03-03 23:39:12] headers: {
[app-frontend] [2022-03-03 23:39:12] host: 'mydomain.com',
[app-frontend] [2022-03-03 23:39:12] 'accept-encoding': 'gzip',
[app-frontend] [2022-03-03 23:39:12] 'x-forwarded-for': '2001:818:e889:6600:f4f5:79c0:beb7:etc etc etc',
[app-frontend] [2022-03-03 23:39:12] 'x-forwarded-proto': 'https',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua-mobile': '?0',
[app-frontend] [2022-03-03 23:39:12] 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
[app-frontend] [2022-03-03 23:39:12] 'sec-ch-ua-platform': '"macOS"',
[app-frontend] [2022-03-03 23:39:12] accept: '*/*',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-site': 'same-origin',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-mode': 'cors',
[app-frontend] [2022-03-03 23:39:12] 'sec-fetch-dest': 'empty',
[app-frontend] [2022-03-03 23:39:12] referer: 'mydomain.com/login',
[app-frontend] [2022-03-03 23:39:12] 'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7',
[app-frontend] [2022-03-03 23:39:12] cookie: 'jwt=75%7C4VyknPf8Jb2papbla-bla-bla',
[app-frontend] [2022-03-03 23:39:12] 'cdn-loop': 'cloudflare',
[app-frontend] [2022-03-03 23:39:12] 'do-connecting-ip': '2001:818:etc',
[app-frontend] [2022-03-03 23:39:12] 'Content-Type': 'application/json',
[app-frontend] [2022-03-03 23:39:12] Accept: 'application/json'
[app-frontend] [2022-03-03 23:39:12] }
[app-frontend] [2022-03-03 23:39:12] }
[app-frontend] [2022-03-03 23:39:12] EERRRROOORRRRRR!!!! THIS SHOULD NEVER BE CALLED, SINCE LARAVEL SHOULD ANSWER THIS CALL, NOT NEXTJS API!!!!!
The last line of the logs above only exists because Axios is calling the wrong domain during NextJS SSR. So, whatever I do, the request is always hitting mydomain.com/api/me
and never the subdomain/Laravel API at api.mydomain.com
. I'm doing all of this in DigitalOcean Apps platform. Using the console, I could manually run a debug.js
file like node debug.js
and it could fetch correctly the URL/payload. But, inside NextJS, the baseURL
is ignored, and the request always goes to NextJS.
I don't know what else I should do here. Because the login
route goes fine. I'm not sure if it's because of the config.headers.host
that is preventing the request to go to the subdomain.
Any help is very appreciated.