2026-01-23 15:57:08 +00:00
/ * *
* Shared utility to check for deprecated authentication environment variables .
* Used by both prebuild . mts ( build time ) and startServer . js ( Docker runtime ) .
*
* IMPORTANT : Keep this file as CommonJS ( . js ) for compatibility with startServer . js
* /
const MIGRATION _DOC _BASE = 'https://lobehub.com/docs/self-hosting/advanced/auth' ;
/ * *
* Deprecated environment variable checks configuration
* @ type { Array < {
* name : string ;
* getVars : ( ) => string [ ] ;
* message : string ;
* docUrl ? : string ;
* formatVar ? : ( envVar : string ) => string ;
2026-01-25 16:11:47 +00:00
* severity ? : 'error' | 'warning' ;
2026-01-23 15:57:08 +00:00
* } > }
* /
const DEPRECATED _CHECKS = [
{
docUrl : ` ${ MIGRATION _DOC _BASE } /nextauth-to-betterauth ` ,
getVars : ( ) =>
Object . keys ( process . env ) . filter (
( key ) => key . startsWith ( 'NEXT_AUTH' ) || key . startsWith ( 'NEXTAUTH' ) ,
) ,
message : 'NextAuth has been removed from LobeChat. Please migrate to Better Auth.' ,
name : 'NextAuth' ,
} ,
{
docUrl : ` ${ MIGRATION _DOC _BASE } /clerk-to-betterauth ` ,
getVars : ( ) =>
[ 'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY' , 'CLERK_SECRET_KEY' , 'CLERK_WEBHOOK_SECRET' ] . filter (
( key ) => process . env [ key ] ,
) ,
message : 'Clerk has been removed from LobeChat. Please migrate to Better Auth.' ,
name : 'Clerk' ,
} ,
{
formatVar : ( envVar ) => {
const mapping = {
2026-01-24 10:04:45 +00:00
ENABLE _MAGIC _LINK : 'AUTH_ENABLE_MAGIC_LINK' ,
2026-01-23 15:57:08 +00:00
NEXT _PUBLIC _AUTH _EMAIL _VERIFICATION : 'AUTH_EMAIL_VERIFICATION' ,
2026-01-24 10:04:45 +00:00
NEXT _PUBLIC _ENABLE _MAGIC _LINK : 'AUTH_ENABLE_MAGIC_LINK' ,
2026-01-23 15:57:08 +00:00
} ;
return ` ${ envVar } → Please use ${ mapping [ envVar ] } instead ` ;
} ,
getVars : ( ) =>
2026-01-24 10:04:45 +00:00
[
'ENABLE_MAGIC_LINK' ,
'NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION' ,
'NEXT_PUBLIC_ENABLE_MAGIC_LINK' ,
] . filter ( ( key ) => process . env [ key ] ) ,
2026-01-23 15:57:08 +00:00
message : 'Please update to the new environment variable names.' ,
name : 'Deprecated Auth' ,
} ,
2026-01-24 10:04:45 +00:00
{
getVars : ( ) => ( process . env [ 'NEXT_PUBLIC_SERVICE_MODE' ] ? [ 'NEXT_PUBLIC_SERVICE_MODE' ] : [ ] ) ,
message :
'LobeChat 2.0 no longer supports client-side database mode. This environment variable is now obsolete and can be removed.' ,
name : 'Service Mode' ,
} ,
{
getVars : ( ) => ( process . env [ 'ACCESS_CODE' ] ? [ 'ACCESS_CODE' ] : [ ] ) ,
message :
'ACCESS_CODE is no longer supported in LobeChat 2.0. Please use Better Auth authentication system instead.' ,
name : 'Access Code' ,
} ,
{
getVars : ( ) =>
process . env [ 'NEXT_PUBLIC_ENABLE_BETTER_AUTH' ] ? [ 'NEXT_PUBLIC_ENABLE_BETTER_AUTH' ] : [ ] ,
message :
'NEXT_PUBLIC_ENABLE_BETTER_AUTH is no longer needed. Better Auth is now automatically detected via AUTH_SECRET presence.' ,
name : 'Better Auth Flag' ,
} ,
{
getVars : ( ) => [ 'NEXT_PUBLIC_AUTH_URL' , 'AUTH_URL' ] . filter ( ( key ) => process . env [ key ] ) ,
message :
'AUTH_URL is no longer needed. The authentication URL is now automatically detected from request headers.' ,
name : 'Auth URL' ,
} ,
{
docUrl : ` ${ MIGRATION _DOC _BASE } /nextauth-to-betterauth ` ,
formatVar : ( envVar ) => {
const mapping = {
AUTH _AZURE _AD _ID : 'AUTH_MICROSOFT_ID' ,
AUTH _AZURE _AD _SECRET : 'AUTH_MICROSOFT_SECRET' ,
2026-02-02 05:35:54 +00:00
AUTH _AZURE _AD _TENANT _ID : 'AUTH_MICROSOFT_TENANT_ID' ,
2026-01-24 10:04:45 +00:00
AZURE _AD _CLIENT _ID : 'AUTH_MICROSOFT_ID' ,
AZURE _AD _CLIENT _SECRET : 'AUTH_MICROSOFT_SECRET' ,
2026-02-02 05:35:54 +00:00
AZURE _AD _TENANT _ID : 'AUTH_MICROSOFT_TENANT_ID' ,
2026-01-24 10:04:45 +00:00
} ;
return ` ${ envVar } → ${ mapping [ envVar ] } ` ;
} ,
getVars : ( ) =>
[
'AZURE_AD_CLIENT_ID' ,
'AZURE_AD_CLIENT_SECRET' ,
'AZURE_AD_TENANT_ID' ,
'AUTH_AZURE_AD_ID' ,
'AUTH_AZURE_AD_SECRET' ,
'AUTH_AZURE_AD_TENANT_ID' ,
] . filter ( ( key ) => process . env [ key ] ) ,
message :
'Azure AD provider has been renamed to Microsoft. Please update your environment variables.' ,
name : 'Azure AD' ,
} ,
{
formatVar : ( envVar ) => {
const mapping = {
ZITADEL _CLIENT _ID : 'AUTH_ZITADEL_ID' ,
ZITADEL _CLIENT _SECRET : 'AUTH_ZITADEL_SECRET' ,
ZITADEL _ISSUER : 'AUTH_ZITADEL_ISSUER' ,
} ;
return ` ${ envVar } → Please use ${ mapping [ envVar ] } instead ` ;
} ,
getVars : ( ) =>
[ 'ZITADEL_CLIENT_ID' , 'ZITADEL_CLIENT_SECRET' , 'ZITADEL_ISSUER' ] . filter (
( key ) => process . env [ key ] ,
) ,
message : 'ZITADEL environment variables have been renamed.' ,
name : 'ZITADEL' ,
} ,
{
formatVar : ( ) => 'OIDC_JWKS_KEY → Please use JWKS_KEY instead' ,
getVars : ( ) => ( process . env [ 'OIDC_JWKS_KEY' ] ? [ 'OIDC_JWKS_KEY' ] : [ ] ) ,
message : 'OIDC_JWKS_KEY has been renamed to JWKS_KEY.' ,
name : 'OIDC JWKS' ,
} ,
2026-01-24 12:30:54 +00:00
{
formatVar : ( ) => 'APP_URL should not end with a trailing slash' ,
getVars : ( ) => ( process . env [ 'APP_URL' ] ? . endsWith ( '/' ) ? [ 'APP_URL' ] : [ ] ) ,
message :
'APP_URL ends with a trailing slash which causes double slashes in redirect URLs (e.g., https://example.com//). Please remove the trailing slash.' ,
name : 'APP_URL Trailing Slash' ,
} ,
2026-01-25 15:00:00 +00:00
{
docUrl : ` ${ MIGRATION _DOC _BASE } /providers/casdoor ` ,
getVars : ( ) => {
const providers = process . env [ 'AUTH_SSO_PROVIDERS' ] || '' ;
if ( providers . includes ( 'casdoor' ) && ! process . env [ 'CASDOOR_WEBHOOK_SECRET' ] ) {
return [ 'CASDOOR_WEBHOOK_SECRET' ] ;
}
return [ ] ;
} ,
message :
2026-01-25 16:11:47 +00:00
'Casdoor webhook is recommended for syncing user data (email, avatar, etc.) to LobeChat. This is especially important for users migrating from NextAuth to Better Auth - users without email configured in Casdoor will not be able to login. Consider configuring CASDOOR_WEBHOOK_SECRET following the documentation.' ,
2026-01-25 15:00:00 +00:00
name : 'Casdoor Webhook' ,
2026-01-25 16:11:47 +00:00
severity : 'warning' ,
2026-01-25 15:00:00 +00:00
} ,
{
docUrl : ` ${ MIGRATION _DOC _BASE } /providers/logto ` ,
getVars : ( ) => {
const providers = process . env [ 'AUTH_SSO_PROVIDERS' ] || '' ;
if ( providers . includes ( 'logto' ) && ! process . env [ 'LOGTO_WEBHOOK_SIGNING_KEY' ] ) {
return [ 'LOGTO_WEBHOOK_SIGNING_KEY' ] ;
}
return [ ] ;
} ,
message :
2026-01-25 16:11:47 +00:00
'Logto webhook is recommended for syncing user data (email, avatar, etc.) to LobeChat. This is especially important for users migrating from NextAuth to Better Auth - users without email configured in Logto will not be able to login. Consider configuring LOGTO_WEBHOOK_SIGNING_KEY following the documentation.' ,
2026-01-25 15:00:00 +00:00
name : 'Logto Webhook' ,
2026-01-25 16:11:47 +00:00
severity : 'warning' ,
2026-01-25 15:00:00 +00:00
} ,
2026-01-24 10:04:45 +00:00
{
docUrl : ` ${ MIGRATION _DOC _BASE } /nextauth-to-betterauth ` ,
formatVar : ( envVar ) => {
const mapping = {
2026-02-02 05:35:54 +00:00
AUTH _MICROSOFT _ENTRA _ID _BASE _URL : 'AUTH_MICROSOFT_AUTHORITY_URL' ,
2026-01-24 10:04:45 +00:00
AUTH _MICROSOFT _ENTRA _ID _ID : 'AUTH_MICROSOFT_ID' ,
AUTH _MICROSOFT _ENTRA _ID _SECRET : 'AUTH_MICROSOFT_SECRET' ,
2026-02-02 05:35:54 +00:00
AUTH _MICROSOFT _ENTRA _ID _TENANT _ID : 'AUTH_MICROSOFT_TENANT_ID' ,
2026-01-24 10:04:45 +00:00
} ;
return ` ${ envVar } → ${ mapping [ envVar ] } ` ;
} ,
getVars : ( ) =>
[
'AUTH_MICROSOFT_ENTRA_ID_ID' ,
'AUTH_MICROSOFT_ENTRA_ID_SECRET' ,
'AUTH_MICROSOFT_ENTRA_ID_TENANT_ID' ,
'AUTH_MICROSOFT_ENTRA_ID_BASE_URL' ,
] . filter ( ( key ) => process . env [ key ] ) ,
message :
'Microsoft Entra ID provider has been renamed to Microsoft. Please update your environment variables.' ,
name : 'Microsoft Entra ID' ,
} ,
2026-01-27 14:14:58 +00:00
{
docUrl : MIGRATION _DOC _BASE ,
getVars : ( ) => {
const hasEmailService =
process . env [ 'SMTP_HOST' ] || process . env [ 'EMAIL_SERVICE_PROVIDER' ] === 'resend' ;
const hasEmailVerification = process . env [ 'AUTH_EMAIL_VERIFICATION' ] === '1' ;
if ( hasEmailService && ! hasEmailVerification ) {
return [ 'AUTH_EMAIL_VERIFICATION' ] ;
}
return [ ] ;
} ,
message :
'Email service is configured but email verification is disabled. Consider setting AUTH_EMAIL_VERIFICATION=1 to verify user email ownership during registration.' ,
name : 'Email Verification' ,
severity : 'warning' ,
} ,
2026-01-23 15:57:08 +00:00
] ;
/ * *
2026-01-25 16:11:47 +00:00
* Print a single deprecation block ( error or warning )
2026-01-23 15:57:08 +00:00
* /
2026-01-25 16:11:47 +00:00
function printIssueBlock ( name , vars , message , docUrl , formatVar , severity = 'error' ) {
const isWarning = severity === 'warning' ;
const icon = isWarning ? '⚠️' : '❌' ;
const log = isWarning ? console . warn : console . error ;
log ( ` \n ${ icon } ${ name } ` ) ;
log ( '─' . repeat ( 50 ) ) ;
2026-02-02 05:35:54 +00:00
log (
isWarning
? 'Missing recommended environment variables:'
: 'Detected deprecated environment variables:' ,
) ;
2026-01-23 15:57:08 +00:00
for ( const envVar of vars ) {
2026-01-25 16:11:47 +00:00
log ( ` • ${ formatVar ? formatVar ( envVar ) : envVar } ` ) ;
2026-01-23 15:57:08 +00:00
}
2026-01-25 16:11:47 +00:00
log ( ` \n ${ message } ` ) ;
2026-01-23 15:57:08 +00:00
if ( docUrl ) {
2026-01-25 16:11:47 +00:00
log ( ` 📖 Documentation: ${ docUrl } ` ) ;
2026-01-23 15:57:08 +00:00
}
}
/ * *
* Check for deprecated authentication environment variables and exit if found
* @ param { object } options
* @ param { string } [ options . action = 'redeploy' ] - Action hint in error message ( 'redeploy' or 'restart' )
* /
function checkDeprecatedAuth ( options = { } ) {
const { action = 'redeploy' } = options ;
2026-01-25 16:11:47 +00:00
const errors = [ ] ;
const warnings = [ ] ;
2026-01-23 15:57:08 +00:00
for ( const check of DEPRECATED _CHECKS ) {
const foundVars = check . getVars ( ) ;
if ( foundVars . length > 0 ) {
2026-01-25 16:11:47 +00:00
const issue = { ... check , foundVars } ;
if ( check . severity === 'warning' ) {
warnings . push ( issue ) ;
} else {
errors . push ( issue ) ;
}
}
}
// Print warnings (non-blocking)
if ( warnings . length > 0 ) {
console . warn ( '\n' + '═' . repeat ( 70 ) ) ;
console . warn ( ` ⚠️ WARNING: Found ${ warnings . length } recommended configuration(s) missing ` ) ;
console . warn ( '═' . repeat ( 70 ) ) ;
for ( const issue of warnings ) {
2026-02-02 05:35:54 +00:00
printIssueBlock (
issue . name ,
issue . foundVars ,
issue . message ,
issue . docUrl ,
issue . formatVar ,
'warning' ,
) ;
2026-01-23 15:57:08 +00:00
}
2026-01-25 16:11:47 +00:00
console . warn ( '\n' + '═' . repeat ( 70 ) ) ;
console . warn ( 'These are recommendations. Your application will still run.' ) ;
console . warn ( '═' . repeat ( 70 ) + '\n' ) ;
2026-01-23 15:57:08 +00:00
}
2026-01-24 10:04:45 +00:00
2026-01-25 16:11:47 +00:00
// Print errors and exit (blocking)
if ( errors . length > 0 ) {
2026-01-24 10:04:45 +00:00
console . error ( '\n' + '═' . repeat ( 70 ) ) ;
2026-02-02 05:35:54 +00:00
console . error ( ` ❌ ERROR: Found ${ errors . length } deprecated environment variable issue(s)! ` ) ;
2026-01-24 10:04:45 +00:00
console . error ( '═' . repeat ( 70 ) ) ;
2026-01-25 16:11:47 +00:00
for ( const issue of errors ) {
2026-02-02 05:35:54 +00:00
printIssueBlock (
issue . name ,
issue . foundVars ,
issue . message ,
issue . docUrl ,
issue . formatVar ,
'error' ,
) ;
2026-01-24 10:04:45 +00:00
}
console . error ( '\n' + '═' . repeat ( 70 ) ) ;
console . error ( ` Please update your environment variables and ${ action } . ` ) ;
console . error ( '═' . repeat ( 70 ) + '\n' ) ;
process . exit ( 1 ) ;
}
2026-01-23 15:57:08 +00:00
}
module . exports = { checkDeprecatedAuth } ;