Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MostofaL's avatar

Stateless OTP Authentication in Laravel and Next.js - How to prevent otp hijacking

I'm working on a project where I have a Laravel application serving as the backend and a Next.js application as the frontend. These two components are synchronized using Sanctum. I plan to switch from Sanctum to Passport. thereby my goal is to remove all dependencies on sessions from the project.

Currently, I've implemented OTP (One-Time Password) login functionality, which relies on the session. When an OTP code is generated, it's stored in the session just before being sent to the user via SMS or email. The purpose of this approach is to ensure that the same user who requested the OTP code is the one attempting to log in.

However, I want to transition to a stateless architecture. How can I achieve OTP authentication without relying on sessions? Here are my considerations:

IP and User Agent Verification:

One suggestion I came across is to store information like the user's IP address and user agent during the initial request. When validating the OTP code, these details can be checked. To my understanding, the Backend (Laravel) doesn't have direct access to the client's IP address. However, the frontend(Next.js) can access this information. I considered forwarding the client's IP address via headers to the Laravel backend, but I discovered that this data can be faked.

My Questions:

  1. What is the best approach to achieve stateless OTP authentication in this scenario?
  2. How can I securely validate OTP codes without relying on sessions?
  3. Is there a reliable way to obtain the client's IP address in Laravel when using Passport?

Any insights or guidance would be greatly appreciated! 🙌

0 likes
3 replies
JussiMannisto's avatar
Level 50

The backend has access to the IP address. You can get it from any request object with $request->ip(). But IP addresses are not unique to users, so it's not a foolproof way of identifying them.

You could (for example) generate a token associated with the authentication request, store it in the client, and then pass that along when completing the login. That way you'll know it's the same client that requested the login.

MostofaL's avatar

@JussiMannisto thanks, I'll try to generate that token you've mentioned. By storing in the client, did you mean cookies?

and for the first part of our response, are you sure the correct IP is available? as I know, While Next.js does receive the original IP address and user agent in the client request, it often modifies these headers before forwarding them to the backend API for security and privacy reasons. Next.js acts as the client in this scenario. It fetches data from the Laravel API, not the other way around. Therefore, the original IP address and user agent associated with the user's browser are not directly accessible to the Laravel application through the HTTP request.

JussiMannisto's avatar

@MostofaL

thanks, I'll try to generate that token you've mentioned. By storing in the client, did you mean cookies?

Cookies or localStorage, your pick.

and for the first part of our response, are you sure the correct IP is available? as I know, While Next.js does receive the original IP address and user agent in the client request, it often modifies these headers before forwarding them to the backend API for security and privacy reasons.

If your browser sends a request to the backend and receives a response, the backend MUST know your IP. How else would the response get routed back to you? Source address is part of the IP packet header and Next.js has no control over it.

Please or to participate in this conversation.