mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-13 02:45:02 +02:00
Force re-login if using old token, show alert if admin user, add isOldToken flag to user
This commit is contained in:
parent
8dbe1e4e5d
commit
e59babdf24
3 changed files with 44 additions and 3 deletions
|
@ -40,6 +40,15 @@
|
||||||
|
|
||||||
<p v-if="error" class="text-error text-center py-2">{{ error }}</p>
|
<p v-if="error" class="text-error text-center py-2">{{ error }}</p>
|
||||||
|
|
||||||
|
<div v-if="showNewAuthSystemAdminMessage" class="mb-4">
|
||||||
|
<widgets-alert type="warning">
|
||||||
|
<div>
|
||||||
|
<p>Authentication has been improved for security. All users will be required to re-login.</p>
|
||||||
|
<a href="https://github.com/advplyr/audiobookshelf/discussions/4460" target="_blank" class="underline">More info</a>
|
||||||
|
</div>
|
||||||
|
</widgets-alert>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form v-show="login_local" @submit.prevent="submitForm">
|
<form v-show="login_local" @submit.prevent="submitForm">
|
||||||
<label class="text-xs text-gray-300 uppercase">{{ $strings.LabelUsername }}</label>
|
<label class="text-xs text-gray-300 uppercase">{{ $strings.LabelUsername }}</label>
|
||||||
<ui-text-input v-model.trim="username" :disabled="processing" class="mb-3 w-full" inputName="username" />
|
<ui-text-input v-model.trim="username" :disabled="processing" class="mb-3 w-full" inputName="username" />
|
||||||
|
@ -85,7 +94,8 @@ export default {
|
||||||
MetadataPath: '',
|
MetadataPath: '',
|
||||||
login_local: true,
|
login_local: true,
|
||||||
login_openid: false,
|
login_openid: false,
|
||||||
authFormData: null
|
authFormData: null,
|
||||||
|
showNewAuthSystemAdminMessage: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -184,6 +194,7 @@ export default {
|
||||||
},
|
},
|
||||||
async submitForm() {
|
async submitForm() {
|
||||||
this.error = null
|
this.error = null
|
||||||
|
this.showNewAuthSystemAdminMessage = false
|
||||||
this.processing = true
|
this.processing = true
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
@ -217,15 +228,28 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
// Force re-login if user is using an old token with no expiration
|
||||||
|
if (res.user.isOldToken) {
|
||||||
|
if (res.user.type === 'admin' || res.user.type === 'root') {
|
||||||
|
this.username = res.user.username
|
||||||
|
// Show message to admin users about new auth system
|
||||||
|
this.showNewAuthSystemAdminMessage = true
|
||||||
|
} else {
|
||||||
|
// Regular users just shown login
|
||||||
|
this.username = res.user.username
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
this.setUser(res)
|
this.setUser(res)
|
||||||
this.processing = false
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Authorize error', error)
|
console.error('Authorize error', error)
|
||||||
this.processing = false
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
checkStatus() {
|
checkStatus() {
|
||||||
this.processing = true
|
this.processing = true
|
||||||
|
|
|
@ -492,6 +492,7 @@ class Auth {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!refreshToken) {
|
if (!refreshToken) {
|
||||||
|
Logger.error(`[Auth] Failed to refresh token. No refresh token provided`)
|
||||||
return res.status(401).json({ error: 'No refresh token provided' })
|
return res.status(401).json({ error: 'No refresh token provided' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,6 +503,7 @@ class Auth {
|
||||||
const decoded = jwt.verify(refreshToken, global.ServerSettings.tokenSecret)
|
const decoded = jwt.verify(refreshToken, global.ServerSettings.tokenSecret)
|
||||||
|
|
||||||
if (decoded.type !== 'refresh') {
|
if (decoded.type !== 'refresh') {
|
||||||
|
Logger.error(`[Auth] Failed to refresh token. Invalid token type: ${decoded.type}`)
|
||||||
return res.status(401).json({ error: 'Invalid token type' })
|
return res.status(401).json({ error: 'Invalid token type' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,6 +512,7 @@ class Auth {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
|
Logger.error(`[Auth] Failed to refresh token. Session not found for refresh token: ${refreshToken}`)
|
||||||
return res.status(401).json({ error: 'Invalid refresh token' })
|
return res.status(401).json({ error: 'Invalid refresh token' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +525,7 @@ class Auth {
|
||||||
|
|
||||||
const user = await Database.userModel.getUserById(decoded.userId)
|
const user = await Database.userModel.getUserById(decoded.userId)
|
||||||
if (!user?.isActive) {
|
if (!user?.isActive) {
|
||||||
|
Logger.error(`[Auth] Failed to refresh token. User not found or inactive for user id: ${decoded.userId}`)
|
||||||
return res.status(401).json({ error: 'User not found or inactive' })
|
return res.status(401).json({ error: 'User not found or inactive' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1128,6 +1132,16 @@ class Auth {
|
||||||
done(null, null)
|
done(null, null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Temporary flag to report old tokens to users
|
||||||
|
// May be a better place for this but here means we dont have to decode the token again
|
||||||
|
if (!jwt_payload.exp && !user.isOldToken) {
|
||||||
|
Logger.debug(`[Auth] User ${user.username} is using an access token without an expiration`)
|
||||||
|
user.isOldToken = true
|
||||||
|
} else if (jwt_payload.exp && user.isOldToken !== undefined) {
|
||||||
|
delete user.isOldToken
|
||||||
|
}
|
||||||
|
|
||||||
// approve login
|
// approve login
|
||||||
done(null, user)
|
done(null, user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -522,6 +522,9 @@ class User extends Model {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
// TODO: Old non-expiring token
|
// TODO: Old non-expiring token
|
||||||
token: this.type === 'root' && hideRootToken ? '' : this.token,
|
token: this.type === 'root' && hideRootToken ? '' : this.token,
|
||||||
|
// TODO: Temporary flag not saved in db that is set in Auth.js jwtAuthCheck
|
||||||
|
// Necessary to detect apps using old tokens that no longer match the old token stored on the user
|
||||||
|
isOldToken: this.isOldToken,
|
||||||
mediaProgress: this.mediaProgresses?.map((mp) => mp.getOldMediaProgress()) || [],
|
mediaProgress: this.mediaProgresses?.map((mp) => mp.getOldMediaProgress()) || [],
|
||||||
seriesHideFromContinueListening: [...seriesHideFromContinueListening],
|
seriesHideFromContinueListening: [...seriesHideFromContinueListening],
|
||||||
bookmarks: this.bookmarks?.map((b) => ({ ...b })) || [],
|
bookmarks: this.bookmarks?.map((b) => ({ ...b })) || [],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue