Skip to content

Commit

Permalink
feat: support for forwardAuth
Browse files Browse the repository at this point in the history
  • Loading branch information
Janhouse committed Nov 28, 2023
1 parent c58261c commit 557af26
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 14 deletions.
9 changes: 9 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ info:
- **Cookie Authentication**: A valid sign-in to the `/auth/plex` or `/auth/local` will generate a valid authentication cookie.
- **API Key Authentication**: Sign-in is also possible by passing an `X-Api-Key` header along with a valid API Key generated by Overseerr.
- **ForwardAuth Authentication**: Sign-in is also possible by passing an `X-Forwarded-User` header containing user's e-mail.
tags:
- name: public
description: Public API endpoints requiring no authentication.
Expand Down Expand Up @@ -171,6 +172,9 @@ components:
defaultPermissions:
type: number
example: 32
enableForwardAuth:
type: boolean
example: true
PlexLibrary:
type: object
properties:
Expand Down Expand Up @@ -1921,6 +1925,10 @@ components:
type: apiKey
in: header
name: X-Api-Key
forwardAuth:
type: apiKey
in: header
name: X-Forwarded-User

paths:
/status:
Expand Down Expand Up @@ -6804,3 +6812,4 @@ paths:
security:
- cookieAuth: []
- apiKey: []
- forwardAuth: []
1 change: 1 addition & 0 deletions server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface PublicSettingsResponse {
locale: string;
emailEnabled: boolean;
newPlexLogin: boolean;
enableForwardAuth: boolean;
}

export interface CacheItem {
Expand Down
26 changes: 25 additions & 1 deletion server/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ export const checkUser: Middleware = async (req, _res, next) => {
}

user = await userRepository.findOne({ where: { id: userId } });
} else if (req.header('x-forwarded-user')) {
const userRepository = getRepository(User);
user = await userRepository.findOne({
where: { email: req.header('x-forwarded-user') },
});

if (user) {
req.user = user;
}

req.locale = user?.settings?.locale
? user.settings.locale
: settings.main.locale;
} else if (req.session?.userId) {
const userRepository = getRepository(User);

Expand All @@ -44,7 +57,18 @@ export const isAuthenticated = (
permissions?: Permission | Permission[],
options?: PermissionCheckOptions
): Middleware => {
const authMiddleware: Middleware = (req, res, next) => {
const authMiddleware: Middleware = async (req, res, next) => {
if (req.header('x-forwarded-user')) {
const userRepository = getRepository(User);
const user = await userRepository.findOne({
where: { email: req.header('x-forwarded-user') },
});

if (user) {
req.user = user;
}
}

if (!req.user || !req.user.hasPermission(permissions ?? 0, options)) {
res.status(403).json({
status: 403,
Expand Down
6 changes: 2 additions & 4 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SettingsProvider } from '@app/context/SettingsContext';
import { UserContext } from '@app/context/UserContext';
import type { User } from '@app/hooks/useUser';
import '@app/styles/globals.css';
import { getRequestHeaders } from '@app/utils/localRequestHelper';
import { polyfillIntl } from '@app/utils/polyfillIntl';
import { MediaServerType } from '@server/constants/server';
import type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';
Expand Down Expand Up @@ -215,10 +216,7 @@ CoreApp.getInitialProps = async (initialProps) => {
const response = await axios.get<User>(
`http://localhost:${process.env.PORT || 5055}/api/v1/auth/me`,
{
headers:
ctx.req && ctx.req.headers.cookie
? { cookie: ctx.req.headers.cookie }
: undefined,
headers: getRequestHeaders(ctx),
}
);
user = response.data;
Expand Down
5 changes: 2 additions & 3 deletions src/pages/collection/[collectionId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CollectionDetails from '@app/components/CollectionDetails';
import { getRequestHeaders } from '@app/utils/localRequestHelper';
import type { Collection } from '@server/models/Collection';
import axios from 'axios';
import type { GetServerSideProps, NextPage } from 'next';
Expand All @@ -19,9 +20,7 @@ export const getServerSideProps: GetServerSideProps<
ctx.query.collectionId
}`,
{
headers: ctx.req?.headers?.cookie
? { cookie: ctx.req.headers.cookie }
: undefined,
headers: getRequestHeaders(ctx),
}
);

Expand Down
5 changes: 2 additions & 3 deletions src/pages/movie/[movieId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import MovieDetails from '@app/components/MovieDetails';
import { getRequestHeaders } from '@app/utils/localRequestHelper';
import type { MovieDetails as MovieDetailsType } from '@server/models/Movie';
import axios from 'axios';
import type { GetServerSideProps, NextPage } from 'next';
Expand All @@ -19,9 +20,7 @@ export const getServerSideProps: GetServerSideProps<MoviePageProps> = async (
ctx.query.movieId
}`,
{
headers: ctx.req?.headers?.cookie
? { cookie: ctx.req.headers.cookie }
: undefined,
headers: getRequestHeaders(ctx),
}
);

Expand Down
5 changes: 2 additions & 3 deletions src/pages/tv/[tvId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import TvDetails from '@app/components/TvDetails';
import { getRequestHeaders } from '@app/utils/localRequestHelper';
import type { TvDetails as TvDetailsType } from '@server/models/Tv';
import axios from 'axios';
import type { GetServerSideProps, NextPage } from 'next';
Expand All @@ -17,9 +18,7 @@ export const getServerSideProps: GetServerSideProps<TvPageProps> = async (
const response = await axios.get<TvDetailsType>(
`http://localhost:${process.env.PORT || 5055}/api/v1/tv/${ctx.query.tvId}`,
{
headers: ctx.req?.headers?.cookie
? { cookie: ctx.req.headers.cookie }
: undefined,
headers: getRequestHeaders(ctx),
}
);

Expand Down
18 changes: 18 additions & 0 deletions src/utils/localRequestHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { NextPageContext } from 'next/dist/shared/lib/utils';
import type { GetServerSidePropsContext, PreviewData } from 'next/types';
import type { ParsedUrlQuery } from 'querystring';

export const getRequestHeaders = (
ctx: NextPageContext | GetServerSidePropsContext<ParsedUrlQuery, PreviewData>
) => {
return ctx.req && ctx.req.headers
? {
...(ctx.req.headers.cookie && {
cookie: ctx.req.headers.cookie,
}),
...(ctx.req.headers['x-forwarded-user'] && {
'x-forwarded-user': ctx.req.headers['x-forwarded-user'] as string,
}),
}
: undefined;
};

0 comments on commit 557af26

Please sign in to comment.