refactor(api): rename Plex auth endpoint (#949)

pull/1012/head
TheCatLady 4 years ago committed by GitHub
parent 970da664b2
commit 09b5019e95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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(
label: 'Auth', 'Failed sign-in attempt from user with incorrect credentials.',
account: { {
ip: req.ip, label: 'Auth',
email: body.email, account: {
password: '__REDACTED__', ip: req.ip,
}, email: body.email,
}); 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();

Loading…
Cancel
Save