Skip to content

Commit fc97595

Browse files
committed
✨(auth) add silent login
Currently users already logged in to the SSO have to click on the login button again to be connected. This extra step should not be necessary. This commit uses the "silent=true" parameter to the login endpoint to avoid the extra step.
1 parent 54fe70d commit fc97595

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ and this project adheres to
2424
- ✨(frontend) link to create new doc #1574
2525
- ♿(frontend) improve accessibility:
2626
- ♿(frontend) add skip to content button for keyboard accessibility #1624
27+
- ✨(auth) add silent login #1689
2728

2829
### Fixed
2930

src/backend/impress/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,8 @@ class Base(Configuration):
525525
SESSION_COOKIE_NAME = "docs_sessionid"
526526

527527
# OIDC - Authorization Code Flow
528+
OIDC_AUTHENTICATE_CLASS = "lasuite.oidc_login.views.OIDCAuthenticationRequestView"
529+
OIDC_CALLBACK_CLASS = "lasuite.oidc_login.views.OIDCAuthenticationCallbackView"
528530
OIDC_CREATE_USER = values.BooleanValue(
529531
default=True,
530532
environ_name="OIDC_CREATE_USER",

src/frontend/apps/impress/src/features/auth/api/useAuthQuery.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query';
33
import { APIError, errorCauses, fetchAPI } from '@/api';
44
import { DEFAULT_QUERY_RETRY } from '@/core';
55

6+
import { attemptSilentLogin, canAttemptSilentLogin } from '../utils';
67
import { User } from './types';
78

89
type UserResponse = User | null;
@@ -11,16 +12,20 @@ type UserResponse = User | null;
1112
* Asynchronously retrieves the current user's data from the API.
1213
* This function is called during frontend initialization to check
1314
* the user's authentication status through a session cookie.
15+
* If a 401 is received, it will attempt silent login if allowed by retry logic.
1416
*
1517
* @async
1618
* @function getMe
1719
* @throws {Error} Throws an error if the API request fails.
18-
* @returns {Promise<User>} A promise that resolves to the user data.
20+
* @returns {Promise<User>} A promise that resolves to the user data or null if not authenticated.
1921
*/
2022
export const getMe = async (): Promise<UserResponse> => {
2123
const response = await fetchAPI(`users/me/`);
2224

2325
if (response.status === 401) {
26+
if (canAttemptSilentLogin()) {
27+
attemptSilentLogin(30); // 30 second retry interval
28+
}
2429
return null;
2530
}
2631

src/frontend/apps/impress/src/features/auth/utils.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,47 @@ export const gotoLogout = () => {
4343
terminateCrispSession();
4444
window.location.replace(LOGOUT_URL);
4545
};
46+
47+
// Silent login utilities
48+
const SILENT_LOGIN_RETRY_KEY = 'silent-login-retry';
49+
50+
const isRetryAllowed = () => {
51+
const lastRetryDate = localStorage.getItem(SILENT_LOGIN_RETRY_KEY);
52+
if (!lastRetryDate) {
53+
return true;
54+
}
55+
const now = new Date();
56+
return now.getTime() > Number(lastRetryDate);
57+
};
58+
59+
const setNextRetryTime = (retryIntervalInSeconds: number) => {
60+
const now = new Date();
61+
const nextRetryTime = now.getTime() + retryIntervalInSeconds * 1000;
62+
localStorage.setItem(SILENT_LOGIN_RETRY_KEY, String(nextRetryTime));
63+
};
64+
65+
const initiateSilentLogin = () => {
66+
const returnTo = window.location.href;
67+
window.location.replace(`${LOGIN_URL}?silent=true&returnTo=${encodeURIComponent(returnTo)}`);
68+
};
69+
70+
/**
71+
* Check if silent login retry is allowed based on the last attempt timestamp.
72+
*/
73+
export const canAttemptSilentLogin = () => {
74+
return isRetryAllowed();
75+
};
76+
77+
/**
78+
* Attempt silent login if retry is allowed.
79+
* Sets a retry interval to prevent infinite loops.
80+
*
81+
* @param retryIntervalInSeconds - Minimum seconds between retry attempts (default: 30)
82+
*/
83+
export const attemptSilentLogin = (retryIntervalInSeconds: number) => {
84+
if (!isRetryAllowed()) {
85+
return;
86+
}
87+
setNextRetryTime(retryIntervalInSeconds);
88+
initiateSilentLogin();
89+
};

0 commit comments

Comments
 (0)