added additional logging and error handling to try to debug a scope parameter failure

pull/3746/head
Mike Kao 5 months ago
parent 76f4461fcd
commit 4f0bc49d7f

@ -431,60 +431,81 @@ authRoutes.post('/reset-password/:guid', async (req, res, next) => {
});
authRoutes.get('/oidc-login', async (req, res, next) => {
const state = randomBytes(32).toString('hex');
const redirectUrl = await getOIDCRedirectUrl(req, state);
res.cookie('oidc-state', state, {
maxAge: 60000,
httpOnly: true,
secure: req.protocol === 'https',
});
return res.redirect(redirectUrl);
});
try {
const state = randomBytes(32).toString('hex');
const redirectUrl = await getOIDCRedirectUrl(req, state);
authRoutes.get('/oidc-callback', async (req, res, next) => {
const settings = getSettings();
const { oidcDomain, oidcClientId, oidcClientSecret } = settings.main;
res.cookie('oidc-state', state, {
maxAge: 60000,
httpOnly: true,
secure: req.protocol === 'https',
});
// Log the initial OIDC callback request
logger.info('Received OIDC callback', { ip: req.ip });
logger.debug('OIDC login initiated', {
path: '/oidc-login',
redirectUrl: redirectUrl,
state: state,
});
if (!settings.main.oidcLogin) {
logger.warn('OIDC sign-in is disabled', { ip: req.ip });
return res.status(500).json({ error: 'OIDC sign-in is disabled.' });
return res.redirect(redirectUrl);
} catch (error) {
logger.error('Failed to initiate OIDC login', {
path: '/oidc-login',
error: error.message,
});
next(error); // Or handle the error as appropriate for your application
}
});
const cookieState = req.cookies['oidc-state'];
const url = new URL(req.url, `${req.protocol}://${req.hostname}`);
const state = url.searchParams.get('state');
const scope = url.searchParams.get('scope'); // Handling additional 'scope' parameter
authRoutes.get('/oidc-callback', async (req, res, next) => {
try {
// State validation
if (!state || cookieState !== state) {
logger.warn('OIDC state mismatch', { ip: req.ip, state, cookieState });
return res.redirect('/login');
const settings = getSettings();
const { oidcDomain, oidcClientId, oidcClientSecret } = settings.main;
if (!settings.main.oidcLogin) {
logger.warn('OIDC sign-in is disabled', { path: '/oidc-callback' });
return res.status(500).json({ error: 'OIDC sign-in is disabled.' });
}
res.clearCookie('oidc-state');
// Code validation
const cookieState = req.cookies['oidc-state'];
const url = new URL(req.url, `${req.protocol}://${req.hostname}`);
const state = url.searchParams.get('state');
const code = url.searchParams.get('code');
if (!code) {
logger.warn('OIDC code missing', { ip: req.ip });
logger.debug('OIDC callback received', {
path: '/oidc-callback',
state: state,
code: code,
cookieState: cookieState,
});
if (!state || state !== cookieState || !code) {
logger.warn('OIDC callback state or code mismatch or missing', {
path: '/oidc-callback',
state: state,
code: code,
cookieState: cookieState,
});
return res.redirect('/login');
}
res.clearCookie('oidc-state');
res.clearCookie('oidc-state');
const wellKnownInfo = await getOIDCWellknownConfiguration(oidcDomain);
// Token request
const callbackUrl = new URL('/api/v1/auth/oidc-callback', `${req.protocol}://${req.headers.host}`);
const callbackUrl = new URL(
'/api/v1/auth/oidc-callback',
`${req.protocol}://${req.headers.host}`
).toString();
const formData = new URLSearchParams();
formData.append('client_secret', oidcClientSecret);
formData.append('grant_type', 'authorization_code');
formData.append('redirect_uri', callbackUrl.toString());
formData.append('redirect_uri', callbackUrl);
formData.append('client_id', oidcClientId);
formData.append('code', code);
formData.append('scope', scope); // Include the 'scope' in the token request
const response = await fetch(wellKnownInfo.token_endpoint, {
method: 'POST',
@ -494,28 +515,41 @@ authRoutes.get('/oidc-callback', async (req, res, next) => {
body: formData,
});
// Validate response
const body = await response.json();
if (body.error) {
logger.warn('Invalid token response', { ip: req.ip, error: body.error });
logger.warn('Failed OIDC token exchange', {
path: '/oidc-callback',
error: body.error,
state: state,
code: code,
});
return res.redirect('/login');
}
// Token validation
const { id_token: idToken } = body;
let decoded;
const decoded = decodeJwt(idToken);
const jwtSchema = createJwtSchema({
oidcClientId: oidcClientId,
oidcDomain: oidcDomain,
});
try {
decoded = decodeJwt(idToken);
const jwtSchema = createJwtSchema({ oidcClientId, oidcDomain });
await jwtSchema.validate(decoded);
} catch (error) {
logger.warn('JWT validation failed', { ip: req.ip, error: error.message });
logger.warn('Invalid JWT in OIDC callback', {
path: '/oidc-callback',
error: error.message,
idToken: idToken,
});
return res.redirect('/login');
}
// Email verification
if (!decoded.email_verified) {
logger.warn('Email not verified', { ip: req.ip, email: decoded.email });
logger.warn('Email not verified in OIDC callback', {
path: '/oidc-callback',
email: decoded.email,
});
return res.redirect('/login');
}
@ -523,23 +557,27 @@ authRoutes.get('/oidc-callback', async (req, res, next) => {
const userRepository = getRepository(User);
let user = await userRepository.findOne({ where: { email: decoded.email } });
// Create user if it doesn't exist
if (!user) {
logger.info('Creating new user', { ip: req.ip, email: decoded.email });
logger.info(`Creating new user from OIDC callback for ${decoded.email}`, {
path: '/oidc-callback',
email: decoded.email,
});
const avatar = gravatarUrl(decoded.email, { default: 'mm', size: 200 });
user = new User({ avatar, username: decoded.email, email: decoded.email, permissions: settings.main.defaultPermissions, plexToken: '', userType: UserType.LOCAL });
await userRepository.save(user);
}
// Session handling
if (req.session) {
req.session.userId = user.id;
}
logger.info('User logged in successfully', { ip: req.ip, userId: user.id });
return res.redirect('/');
} catch (error) {
logger.error('OIDC login error', { ip: req.ip, errorMessage: error.message });
return res.redirect('/login');
logger.error('Error in OIDC callback processing', {
path: '/oidc-callback',
error: error.message,
});
next(error);
}
});

Loading…
Cancel
Save