mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-24 22:26:42 +00:00
fix(oidc): fix QR code login issues caused by OIDC
In implementing OIDC it became necessary to introduce the separation of "GUI Tokens" and "Session Tokens". This breaks QR login because Puter does not set the HTTP-only session cookie when logging in with this flow. Add a middelware to WebServerService to detect QR Code logins and set the appropriate HTTP-only session cookie.
This commit is contained in:
@@ -337,6 +337,34 @@ class WebServerService extends BaseService {
|
||||
next();
|
||||
});
|
||||
|
||||
// When the user visits the main origin (not api/dav subdomain) with ?auth_token=<GUI token>
|
||||
// (e.g. QR login), set the HTTP-only session cookie so user-protected endpoints work.
|
||||
app.use(async (req, res, next) => {
|
||||
const has_subdomain = req.hostname.slice(0, -1 * (config.domain.length + 1)) !== '';
|
||||
if ( has_subdomain ) return next();
|
||||
|
||||
const token = req.query?.auth_token;
|
||||
if ( !token || typeof token !== 'string' ) return next();
|
||||
|
||||
try {
|
||||
const svc_auth = req.services.get('auth');
|
||||
const cleanToken = token.replace('Bearer ', '').trim();
|
||||
const actor = await svc_auth.authenticate_from_token(cleanToken);
|
||||
const session_token = svc_auth.create_session_token_for_session(
|
||||
actor.type.user,
|
||||
actor.type.session,
|
||||
);
|
||||
res.cookie(config.cookie_name, session_token, {
|
||||
sameSite: 'none',
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
});
|
||||
} catch ( _e ) {
|
||||
// Invalid or expired token; do not set cookie
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// Measure data transfer amounts
|
||||
app.use(measure());
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const { Context } = require('../../util/context');
|
||||
module.exports = {
|
||||
route: '/change-username',
|
||||
methods: ['POST'],
|
||||
handler: async (req, res, next) => {
|
||||
handler: async (req, res, _next) => {
|
||||
const user = req.user;
|
||||
const new_username = req.body.new_username;
|
||||
|
||||
|
||||
@@ -355,6 +355,25 @@ class AuthService extends BaseService {
|
||||
}, this.global_config.jwt_secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a session token (hasHttpPowers) for an existing session.
|
||||
* Used when the client authenticated with a GUI token (e.g. QR login via
|
||||
* ?auth_token=) so we can set the HTTP-only cookie and allow user-protected
|
||||
* endpoints (change password, email, username, etc.) to work.
|
||||
*
|
||||
* @param {*} user - User object (must have .uuid).
|
||||
* @param {string} session_uuid - Existing session UUID.
|
||||
* @returns {string} JWT session token.
|
||||
*/
|
||||
create_session_token_for_session (user, session_uuid) {
|
||||
return this.modules.jwt.sign({
|
||||
type: 'session',
|
||||
version: '0.0.0',
|
||||
uuid: session_uuid,
|
||||
user_uid: user.uuid,
|
||||
}, this.global_config.jwt_secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the provided session token is valid and returns the associated user and token.
|
||||
* If the token is not a valid session token or it does not exist in the database, it returns an empty object.
|
||||
|
||||
Reference in New Issue
Block a user