@@ -34,7 +34,7 @@ function getAuthConfig(): { token: string } | { email: string; password: string
3434 return { token : setup . auth_token }
3535 }
3636
37- // Fall back to password (legacy format) - will migrate to token on success
37+ // Fall back to password
3838 if ( setup . admin_email && setup . admin_password ) {
3939 return { email : setup . admin_email , password : setup . admin_password }
4040 }
@@ -53,6 +53,31 @@ function getAuthConfig(): { token: string } | { email: string; password: string
5353 return null
5454}
5555
56+ // Get password credentials for re-auth when token expires
57+ function getPasswordCredentials ( ) : { email : string ; password : string } | null {
58+ // Try setup file first
59+ try {
60+ if ( fs . existsSync ( SETUP_FILE ) ) {
61+ const data = fs . readFileSync ( SETUP_FILE , 'utf-8' )
62+ const setup = JSON . parse ( data )
63+ if ( setup . admin_email && setup . admin_password ) {
64+ return { email : setup . admin_email , password : setup . admin_password }
65+ }
66+ }
67+ } catch {
68+ // Fall through
69+ }
70+
71+ // Try env vars
72+ const email = env . POCKETBASE_ADMIN_EMAIL
73+ const password = env . POCKETBASE_ADMIN_PASSWORD
74+ if ( email && password ) {
75+ return { email, password }
76+ }
77+
78+ return null
79+ }
80+
5681export async function ensureAuth ( ) : Promise < boolean > {
5782 // If already authenticated with valid token, return true
5883 if ( isAuthenticated && pb . authStore . isValid ) {
@@ -93,9 +118,25 @@ export async function ensureAuth(): Promise<boolean> {
93118 saveRefreshedToken ( pb . authStore . token )
94119 return true
95120 } catch {
96- // Token invalid/expired, can't refresh without password
97- console . warn ( '[PB] Saved token invalid, need fresh setup or env vars ' )
121+ // Token invalid/expired - try password fallback from setup file or env vars
122+ console . warn ( '[PB] Saved token expired, trying password fallback... ' )
98123 pb . authStore . clear ( )
124+
125+ // Try setup file password first, then env vars
126+ const creds = getPasswordCredentials ( )
127+ if ( creds ) {
128+ try {
129+ await pb . collection ( '_superusers' ) . authWithPassword ( creds . email , creds . password )
130+ isAuthenticated = true
131+ console . log ( '[PB] Server re-authenticated via password (token was expired)' )
132+ saveRefreshedToken ( pb . authStore . token )
133+ return true
134+ } catch ( e : any ) {
135+ console . error ( '[PB] Password auth failed:' , e . message || e )
136+ }
137+ }
138+
139+ console . error ( '[PB] Auth token expired and no password available. Re-run /setup' )
99140 return false
100141 }
101142 } else {
@@ -115,23 +156,17 @@ export async function ensureAuth(): Promise<boolean> {
115156 }
116157}
117158
118- // Save refreshed token back to setup file (and remove password if present )
159+ // Save refreshed token back to setup file (keeps password for re-auth fallback )
119160function saveRefreshedToken ( token : string ) : void {
120161 try {
121162 if ( ! fs . existsSync ( SETUP_FILE ) ) return
122163
123164 const data = fs . readFileSync ( SETUP_FILE , 'utf-8' )
124165 const setup = JSON . parse ( data )
125166
126- // Update token
167+ // Update token (password stays for re-auth if token expires)
127168 setup . auth_token = token
128169
129- // Remove password if present (migration from legacy format)
130- if ( setup . admin_password ) {
131- delete setup . admin_password
132- console . log ( '[PB] Migrated from password to token-based auth' )
133- }
134-
135170 fs . writeFileSync ( SETUP_FILE , JSON . stringify ( setup ) , { mode : 0o600 } )
136171 } catch {
137172 // Silently fail - not critical
0 commit comments