mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
refactor(api): rename Plex auth endpoint (#949)
This commit is contained in:
@@ -8,7 +8,7 @@ To use Fail2ban with Overseerr, create a new file named `overseerr.local` in you
|
|||||||
|
|
||||||
```
|
```
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = .*\[info\]\[Auth\]\: Failed login attempt.*"ip":"<HOST>"
|
failregex = .*\[info\]\[Auth\]\: Failed sign-in attempt.*"ip":"<HOST>"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then add a jail using this filter in `jail.local`. Please see the [Fail2ban documetation](https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Jails) for details on how to configure the jail.
|
You can then add a jail using this filter in `jail.local`. Please see the [Fail2ban documetation](https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Jails) for details on how to configure the jail.
|
||||||
|
@@ -7,8 +7,8 @@ info:
|
|||||||
|
|
||||||
Two primary authentication methods are supported:
|
Two primary authentication methods are supported:
|
||||||
|
|
||||||
- **Cookie Authentication**: A valid login to the `/auth/login` or `/auth/local` will generate a valid authentication cookie.
|
- **Cookie Authentication**: A valid sign-in to the `/auth/plex` or `/auth/local` will generate a valid authentication cookie.
|
||||||
- **API Key Authentication**: Login is also possible by passing an `X-Api-Key` header along with a valid API Key generated by Overseerr.
|
- **API Key Authentication**: Sign-in is also possible by passing an `X-Api-Key` header along with a valid API Key generated by Overseerr.
|
||||||
tags:
|
tags:
|
||||||
- name: public
|
- name: public
|
||||||
description: Public API endpoints requiring no authentication.
|
description: Public API endpoints requiring no authentication.
|
||||||
@@ -2613,7 +2613,7 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/User'
|
$ref: '#/components/schemas/User'
|
||||||
/auth/login:
|
/auth/plex:
|
||||||
post:
|
post:
|
||||||
summary: Sign in using a Plex token
|
summary: Sign in using a Plex token
|
||||||
description: Takes an `authToken` (Plex token) to log the user in. Generates a session cookie for use in further requests. If the user does not exist, and there are no other users, then a user will be created with full admin privileges. If a user logs in with access to the main Plex server, they will also have an account created, but without any permissions.
|
description: Takes an `authToken` (Plex token) to log the user in. Generates a session cookie for use in further requests. If the user does not exist, and there are no other users, then a user will be created with full admin privileges. If a user logs in with access to the main Plex server, they will also have an account created, but without any permissions.
|
||||||
|
@@ -26,7 +26,7 @@ authRoutes.get('/me', isAuthenticated(), async (req, res) => {
|
|||||||
return res.status(200).json(user);
|
return res.status(200).json(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
authRoutes.post('/login', async (req, res, next) => {
|
authRoutes.post('/plex', async (req, res, next) => {
|
||||||
const settings = getSettings();
|
const settings = getSettings();
|
||||||
const userRepository = getRepository(User);
|
const userRepository = getRepository(User);
|
||||||
const body = req.body as { authToken?: string };
|
const body = req.body as { authToken?: string };
|
||||||
@@ -35,7 +35,7 @@ authRoutes.post('/login', async (req, res, next) => {
|
|||||||
return res.status(500).json({ error: 'You must provide an auth token' });
|
return res.status(500).json({ error: 'You must provide an auth token' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// First we need to use this auth token to get the users email from plex tv
|
// First we need to use this auth token to get the users email from plex.tv
|
||||||
const plextv = new PlexTvAPI(body.authToken);
|
const plextv = new PlexTvAPI(body.authToken);
|
||||||
const account = await plextv.getUser();
|
const account = await plextv.getUser();
|
||||||
|
|
||||||
@@ -45,12 +45,12 @@ authRoutes.post('/login', async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
// Let's check if their plex token is up to date
|
// Let's check if their Plex token is up-to-date
|
||||||
if (user.plexToken !== body.authToken) {
|
if (user.plexToken !== body.authToken) {
|
||||||
user.plexToken = body.authToken;
|
user.plexToken = body.authToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the users avatar with their plex thumbnail (incase it changed)
|
// Update the user's avatar with their Plex thumbnail, in case it changed
|
||||||
user.avatar = account.thumb;
|
user.avatar = account.thumb;
|
||||||
user.email = account.email;
|
user.email = account.email;
|
||||||
user.plexUsername = account.username;
|
user.plexUsername = account.username;
|
||||||
@@ -80,7 +80,7 @@ authRoutes.post('/login', async (req, res, next) => {
|
|||||||
// Double check that we didn't create the first admin user before running this
|
// Double check that we didn't create the first admin user before running this
|
||||||
if (!user) {
|
if (!user) {
|
||||||
// If we get to this point, the user does not already exist so we need to create the
|
// If we get to this point, the user does not already exist so we need to create the
|
||||||
// user _assuming_ they have access to the plex server
|
// user _assuming_ they have access to the Plex server
|
||||||
const mainUser = await userRepository.findOneOrFail({
|
const mainUser = await userRepository.findOneOrFail({
|
||||||
select: ['id', 'plexToken'],
|
select: ['id', 'plexToken'],
|
||||||
order: { id: 'ASC' },
|
order: { id: 'ASC' },
|
||||||
@@ -100,7 +100,7 @@ authRoutes.post('/login', async (req, res, next) => {
|
|||||||
await userRepository.save(user);
|
await userRepository.save(user);
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
'Failed login attempt from user without access to plex server',
|
'Failed sign-in attempt from user without access to the Plex server.',
|
||||||
{
|
{
|
||||||
label: 'Auth',
|
label: 'Auth',
|
||||||
account: {
|
account: {
|
||||||
@@ -112,7 +112,7 @@ authRoutes.post('/login', async (req, res, next) => {
|
|||||||
);
|
);
|
||||||
return next({
|
return next({
|
||||||
status: 403,
|
status: 403,
|
||||||
message: 'You do not have access to this Plex server',
|
message: 'You do not have access to this Plex server.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,11 +139,11 @@ authRoutes.post('/local', async (req, res, next) => {
|
|||||||
const body = req.body as { email?: string; password?: string };
|
const body = req.body as { email?: string; password?: string };
|
||||||
|
|
||||||
if (!settings.main.localLogin) {
|
if (!settings.main.localLogin) {
|
||||||
return res.status(500).json({ error: 'Local user login is disabled' });
|
return res.status(500).json({ error: 'Local user sign-in is disabled.' });
|
||||||
} else if (!body.email || !body.password) {
|
} else if (!body.email || !body.password) {
|
||||||
return res
|
return res.status(500).json({
|
||||||
.status(500)
|
error: 'You must provide both an email address and a password.',
|
||||||
.json({ error: 'You must provide an email and a password' });
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const user = await userRepository.findOne({
|
const user = await userRepository.findOne({
|
||||||
@@ -155,17 +155,20 @@ authRoutes.post('/local', async (req, res, next) => {
|
|||||||
|
|
||||||
// User doesn't exist or credentials are incorrect
|
// User doesn't exist or credentials are incorrect
|
||||||
if (!isCorrectCredentials) {
|
if (!isCorrectCredentials) {
|
||||||
logger.info('Failed login attempt from user with incorrect credentials', {
|
logger.info(
|
||||||
|
'Failed sign-in attempt from user with incorrect credentials.',
|
||||||
|
{
|
||||||
label: 'Auth',
|
label: 'Auth',
|
||||||
account: {
|
account: {
|
||||||
ip: req.ip,
|
ip: req.ip,
|
||||||
email: body.email,
|
email: body.email,
|
||||||
password: '__REDACTED__',
|
password: '__REDACTED__',
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return next({
|
return next({
|
||||||
status: 403,
|
status: 403,
|
||||||
message: 'You do not have access to this Plex server',
|
message: 'Your sign-in credentials are incorrect.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +179,7 @@ authRoutes.post('/local', async (req, res, next) => {
|
|||||||
|
|
||||||
return res.status(200).json(user?.filter() ?? {});
|
return res.status(200).json(user?.filter() ?? {});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Something went wrong when trying to authenticate', {
|
logger.error('Something went wrong while attempting to authenticate.', {
|
||||||
label: 'Auth',
|
label: 'Auth',
|
||||||
error: e.message,
|
error: e.message,
|
||||||
});
|
});
|
||||||
@@ -205,7 +208,9 @@ authRoutes.post('/reset-password', async (req, res) => {
|
|||||||
const body = req.body as { email?: string };
|
const body = req.body as { email?: string };
|
||||||
|
|
||||||
if (!body.email) {
|
if (!body.email) {
|
||||||
return res.status(500).json({ error: 'You must provide an email' });
|
return res
|
||||||
|
.status(500)
|
||||||
|
.json({ error: 'You must provide an email address.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await userRepository.findOne({
|
const user = await userRepository.findOne({
|
||||||
@@ -215,12 +220,12 @@ authRoutes.post('/reset-password', async (req, res) => {
|
|||||||
if (user) {
|
if (user) {
|
||||||
await user.resetPassword();
|
await user.resetPassword();
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
logger.info('Successful request made for recovery link', {
|
logger.info('Successful request made for recovery link.', {
|
||||||
label: 'User Management',
|
label: 'User Management',
|
||||||
context: { ip: req.ip, email: body.email },
|
context: { ip: req.ip, email: body.email },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.info('Failed request made to reset a password', {
|
logger.info('Failed request made to reset a password.', {
|
||||||
label: 'User Management',
|
label: 'User Management',
|
||||||
context: { ip: req.ip, email: body.email },
|
context: { ip: req.ip, email: body.email },
|
||||||
});
|
});
|
||||||
@@ -235,7 +240,7 @@ authRoutes.post('/reset-password/:guid', async (req, res, next) => {
|
|||||||
try {
|
try {
|
||||||
if (!req.body.password || req.body.password?.length < 8) {
|
if (!req.body.password || req.body.password?.length < 8) {
|
||||||
const message =
|
const message =
|
||||||
'Failed to reset password. Password must be atleast 8 characters long.';
|
'Failed to reset password. Password must be at least 8 characters long.';
|
||||||
logger.info(message, {
|
logger.info(message, {
|
||||||
label: 'User Management',
|
label: 'User Management',
|
||||||
context: { ip: req.ip, guid: req.params.guid },
|
context: { ip: req.ip, guid: req.params.guid },
|
||||||
|
@@ -29,13 +29,13 @@ const Login: React.FC = () => {
|
|||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
|
|
||||||
// Effect that is triggered when the `authToken` comes back from the Plex OAuth
|
// Effect that is triggered when the `authToken` comes back from the Plex OAuth
|
||||||
// We take the token and attempt to login. If we get a success message, we will
|
// We take the token and attempt to sign in. If we get a success message, we will
|
||||||
// ask swr to revalidate the user which _should_ come back with a valid user.
|
// ask swr to revalidate the user which _should_ come back with a valid user.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
setProcessing(true);
|
setProcessing(true);
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/api/v1/auth/login', { authToken });
|
const response = await axios.post('/api/v1/auth/plex', { authToken });
|
||||||
|
|
||||||
if (response.data?.id) {
|
if (response.data?.id) {
|
||||||
revalidate();
|
revalidate();
|
||||||
|
@@ -23,7 +23,7 @@ const LoginWithPlex: React.FC<LoginWithPlexProps> = ({ onComplete }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
const response = await axios.post('/api/v1/auth/login', { authToken });
|
const response = await axios.post('/api/v1/auth/plex', { authToken });
|
||||||
|
|
||||||
if (response.data?.email) {
|
if (response.data?.email) {
|
||||||
revalidate();
|
revalidate();
|
||||||
|
Reference in New Issue
Block a user