I am currently developing a system with an ASP.NET Core Web API backend and client applications in both Blazor WebAssembly and .NET MAUI. The authentication flow is based on JWT with rotating refresh tokens; access tokens expire after 3 minutes and refresh tokens after 30 days. We use GraphQL with a single endpoint for the server-client protocol.
On the client side, tokens are stored in the browser’s local storage for web clients and in secure storage for MAUI. Despite being common, storing tokens in local storage is often advised against due to security concerns. The recommended approach is to use HttpOnly cookies, but this solution doesn’t fit our requirements for several reasons:
Single Endpoint Issue: Normally, using HttpOnly cookies for refresh tokens would require a separate endpoint (e.g., “/api/refresh”), but we are constrained to a single GraphQL endpoint.
Client Compatibility: HttpOnly cookies are primarily suited for web clients and not for native applications across different platforms (Windows, iOS, Android).
Security Considerations: Storing both the access and refresh tokens in local storage poses security risks, and switching to a single rotating token would require frequent authorization checks against the database, increasing server load.
Question: What is the best way to store access and long-lived refresh tokens that is secure yet functional across both web and native clients, considering the limitations of GraphQL and the need for a protocol-agnostic solution? Any advice on strategies or architectures that cater to this kind of setup would be greatly appreciated.