fix(auth): do not allow to register in invite mode (#9101)

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto
2026-03-22 20:44:03 +01:00
committed by GitHub
parent 5d410e5a03
commit 15935e9d5f
2 changed files with 34 additions and 7 deletions

View File

@@ -213,6 +213,22 @@ func (m *OAuthManager) CallbackHandler(providerName string, db *gorm.DB, adminEm
})
}
// In invite mode, block new OAuth users who don't have a valid invite code
// to prevent phantom pending records from accumulating in the DB.
// The first user (no users in DB yet) is always allowed through.
if registrationMode == "invite" && inviteCode == "" {
var existing User
if err := db.Where("provider = ? AND subject = ?", providerName, userInfo.Subject).First(&existing).Error; err != nil {
// Check if this would be the first user (always allowed)
var userCount int64
db.Model(&User{}).Count(&userCount)
if userCount > 0 {
// New user without invite code — reject without creating a DB record
return c.Redirect(http.StatusTemporaryRedirect, "/login?error=invite_required")
}
}
}
// Upsert user (with invite code support)
user, err := upsertOAuthUser(db, providerName, userInfo, adminEmail, registrationMode)
if err != nil {

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { apiUrl } from '../utils/basePath'
import './auth.css'
@@ -7,6 +7,7 @@ import './auth.css'
export default function Login() {
const navigate = useNavigate()
const { code: urlInviteCode } = useParams()
const [searchParams] = useSearchParams()
const { authEnabled, user, loading: authLoading, refresh } = useAuth()
const [providers, setProviders] = useState([])
const [hasUsers, setHasUsers] = useState(true)
@@ -42,6 +43,14 @@ export default function Login() {
}
}, [urlInviteCode])
// Show error from OAuth redirect (e.g. invite_required)
useEffect(() => {
const errorParam = searchParams.get('error')
if (errorParam === 'invite_required') {
setError('A valid invite code is required to register')
}
}, [searchParams])
useEffect(() => {
fetch(apiUrl('/api/auth/status'))
.then(r => r.json())
@@ -252,12 +261,14 @@ export default function Login() {
<button type="submit" className="btn btn-primary login-btn-full" disabled={submitting}>
{submitting ? 'Signing in...' : 'Sign In'}
</button>
<p className="login-footer">
Don't have an account?{' '}
<button type="button" className="login-link" onClick={() => { setMode('register'); setError(''); setMessage('') }}>
Register
</button>
</p>
{!(registrationMode === 'invite' && hasUsers && !urlInviteCode) && (
<p className="login-footer">
Don't have an account?{' '}
<button type="button" className="login-link" onClick={() => { setMode('register'); setError(''); setMessage('') }}>
Register
</button>
</p>
)}
</form>
)}