@@ -9,6 +9,12 @@ import {
99} from "react" ;
1010import { GamevaultUser } from "../api" ;
1111import { AuthTokens } from "../types/AuthTokens" ;
12+ import {
13+ AUTH_REFRESH_STORAGE_KEY ,
14+ AUTH_SERVER_STORAGE_KEY ,
15+ getDevAutologinConfig ,
16+ normalizeServerUrl ,
17+ } from "@/utils/authConfig" ;
1218
1319interface LoginArgs {
1420 server : string ;
@@ -38,9 +44,6 @@ interface AuthContextValue {
3844
3945const AuthContext = createContext < AuthContextValue | null > ( null ) ;
4046
41- const REFRESH_KEY = "app_refresh_token" ;
42- const SERVER_KEY = "app_server_url" ;
43-
4447interface InternalJwtPayload {
4548 exp ?: number ;
4649 Exp ?: number ;
@@ -161,7 +164,8 @@ export function AuthProvider({ children }: { children: ReactNode }) {
161164 } , [ ] ) ;
162165 const performRefresh = useCallback ( async ( ) => {
163166 const refreshToken =
164- authRef . current ?. refresh_token || localStorage . getItem ( REFRESH_KEY ) ;
167+ authRef . current ?. refresh_token ||
168+ localStorage . getItem ( AUTH_REFRESH_STORAGE_KEY ) ;
165169 if ( ! refreshToken ) throw new Error ( "Missing refresh token" ) ;
166170 const data = await refreshWithToken ( refreshToken ) ;
167171 if ( ! data ?. access_token )
@@ -170,7 +174,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
170174 authRef . current = merged ;
171175 setAuth ( merged ) ;
172176 if ( merged . refresh_token )
173- localStorage . setItem ( REFRESH_KEY , merged . refresh_token ) ;
177+ localStorage . setItem (
178+ AUTH_REFRESH_STORAGE_KEY ,
179+ merged . refresh_token ,
180+ ) ;
174181 nextTokenRefreshRef . current = computeNextTokenRefresh ( merged . access_token ) ;
175182 } , [ ] ) ;
176183 const ensureFreshToken = useCallback ( async ( ) => {
@@ -210,17 +217,20 @@ export function AuthProvider({ children }: { children: ReactNode }) {
210217 setAuth ( null ) ;
211218 authRef . current = null ;
212219 nextTokenRefreshRef . current = null ;
213- serverRef . current = ( server || "" ) . replace ( / \/ + $ / , "" ) ;
220+ serverRef . current = normalizeServerUrl ( server ) ;
214221 setServerUrl ( serverRef . current ) ;
215- localStorage . setItem ( SERVER_KEY , serverRef . current ) ;
222+ localStorage . setItem ( AUTH_SERVER_STORAGE_KEY , serverRef . current ) ;
216223 try {
217224 if ( ! server || ! username || ! password )
218225 throw new Error ( "All fields are required." ) ;
219226 const authData = await loginBasicRequest ( username , password ) ;
220227 authRef . current = authData ;
221228 setAuth ( authData ) ;
222229 if ( authData . refresh_token )
223- localStorage . setItem ( REFRESH_KEY , authData . refresh_token ) ;
230+ localStorage . setItem (
231+ AUTH_REFRESH_STORAGE_KEY ,
232+ authData . refresh_token ,
233+ ) ;
224234 nextTokenRefreshRef . current = authData . access_token
225235 ? computeNextTokenRefresh ( authData . access_token )
226236 : new Date ( ) ;
@@ -247,15 +257,18 @@ export function AuthProvider({ children }: { children: ReactNode }) {
247257 setAuth ( null ) ;
248258 authRef . current = null ;
249259 nextTokenRefreshRef . current = null ;
250- serverRef . current = ( server || "" ) . replace ( / \/ + $ / , "" ) ;
260+ serverRef . current = normalizeServerUrl ( server ) ;
251261 setServerUrl ( serverRef . current ) ;
252- localStorage . setItem ( SERVER_KEY , serverRef . current ) ;
262+ localStorage . setItem ( AUTH_SERVER_STORAGE_KEY , serverRef . current ) ;
253263 try {
254264 if ( ! tokens ?. access_token ) throw new Error ( "Missing access token" ) ;
255265 authRef . current = tokens ;
256266 setAuth ( tokens ) ;
257267 if ( tokens . refresh_token )
258- localStorage . setItem ( REFRESH_KEY , tokens . refresh_token ) ;
268+ localStorage . setItem (
269+ AUTH_REFRESH_STORAGE_KEY ,
270+ tokens . refresh_token ,
271+ ) ;
259272 nextTokenRefreshRef . current = computeNextTokenRefresh (
260273 tokens . access_token ,
261274 ) ;
@@ -284,13 +297,57 @@ export function AuthProvider({ children }: { children: ReactNode }) {
284297 bootstrapRanRef . current = true ;
285298
286299 ( async ( ) => {
287- const storedRefresh = localStorage . getItem ( REFRESH_KEY ) ;
288- const storedServer = localStorage . getItem ( SERVER_KEY ) ;
300+ const storedRefresh = localStorage . getItem ( AUTH_REFRESH_STORAGE_KEY ) ;
301+ const storedServer = localStorage . getItem ( AUTH_SERVER_STORAGE_KEY ) ;
289302 if ( ! storedRefresh || ! storedServer ) {
290- setBootstrapping ( false ) ;
303+ const devAutologin = getDevAutologinConfig ( ) ;
304+ if ( ! devAutologin ) {
305+ setBootstrapping ( false ) ;
306+ return ;
307+ }
308+
309+ setLoading ( true ) ;
310+ setError ( null ) ;
311+ serverRef . current = devAutologin . server ;
312+ setServerUrl ( serverRef . current ) ;
313+ localStorage . setItem ( AUTH_SERVER_STORAGE_KEY , serverRef . current ) ;
314+ try {
315+ const tokens = await loginBasicRequest (
316+ devAutologin . username ,
317+ devAutologin . password ,
318+ ) ;
319+ if ( ! tokens . access_token ) {
320+ throw new Error ( "No access_token in dev autologin response" ) ;
321+ }
322+ authRef . current = tokens ;
323+ setAuth ( tokens ) ;
324+ if ( tokens . refresh_token ) {
325+ localStorage . setItem (
326+ AUTH_REFRESH_STORAGE_KEY ,
327+ tokens . refresh_token ,
328+ ) ;
329+ }
330+ nextTokenRefreshRef . current = computeNextTokenRefresh (
331+ tokens . access_token ,
332+ ) ;
333+ const me = await fetchCurrentUser ( ) ;
334+ setUser ( me ) ;
335+ } catch ( e ) {
336+ authRef . current = null ;
337+ setAuth ( null ) ;
338+ setUser ( null ) ;
339+ nextTokenRefreshRef . current = null ;
340+ localStorage . removeItem ( AUTH_REFRESH_STORAGE_KEY ) ;
341+ setError (
342+ e instanceof Error ? e . message : "Dev autologin failed." ,
343+ ) ;
344+ } finally {
345+ setLoading ( false ) ;
346+ setBootstrapping ( false ) ;
347+ }
291348 return ;
292349 }
293- serverRef . current = storedServer . replace ( / \/ + $ / , "" ) ;
350+ serverRef . current = normalizeServerUrl ( storedServer ) ;
294351 setServerUrl ( serverRef . current ) ;
295352 try {
296353 const tokens = await refreshWithToken ( storedRefresh ) ;
@@ -299,15 +356,17 @@ export function AuthProvider({ children }: { children: ReactNode }) {
299356 authRef . current = tokens ;
300357 setAuth ( tokens ) ;
301358 if ( tokens . refresh_token )
302- localStorage . setItem ( REFRESH_KEY , tokens . refresh_token ) ;
359+ localStorage . setItem (
360+ AUTH_REFRESH_STORAGE_KEY ,
361+ tokens . refresh_token ,
362+ ) ;
303363 nextTokenRefreshRef . current = computeNextTokenRefresh (
304364 tokens . access_token ,
305365 ) ;
306366 const me = await fetchCurrentUser ( ) ;
307367 setUser ( me ) ;
308368 } catch {
309- localStorage . removeItem ( REFRESH_KEY ) ;
310- localStorage . removeItem ( SERVER_KEY ) ;
369+ localStorage . removeItem ( AUTH_REFRESH_STORAGE_KEY ) ;
311370 authRef . current = null ;
312371 setAuth ( null ) ;
313372 } finally {
@@ -322,7 +381,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
322381 setAuth ( null ) ;
323382 setUser ( null ) ;
324383 setError ( null ) ;
325- localStorage . removeItem ( REFRESH_KEY ) ;
384+ localStorage . removeItem ( AUTH_REFRESH_STORAGE_KEY ) ;
326385 } , [ ] ) ;
327386
328387 const refreshCurrentUser = useCallback ( async ( ) => {
0 commit comments