🚸(auth) implement first draft of silent login with prompt=None
Add initial naive implementation of silent login functionality using prompt=None parameter to request OIDC provider to skip login screen and return proper HTTP error response instead.
This commit is contained in:
@@ -467,6 +467,8 @@ class Base(Configuration):
|
||||
)
|
||||
|
||||
# OIDC - Authorization Code Flow
|
||||
OIDC_AUTHENTICATE_CLASS = "lasuite.oidc_login.views.OIDCAuthenticationRequestView"
|
||||
OIDC_CALLBACK_CLASS = "lasuite.oidc_login.views.OIDCAuthenticationCallbackView"
|
||||
OIDC_CREATE_USER = values.BooleanValue(
|
||||
default=True,
|
||||
environ_name="OIDC_CREATE_USER",
|
||||
|
||||
@@ -2,6 +2,10 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
import { DEFAULT_QUERY_RETRY } from '@/core';
|
||||
import {
|
||||
attemptSilentLogin,
|
||||
canAttemptSilentLogin,
|
||||
} from '@/features/auth/silentLogin';
|
||||
|
||||
import { User } from './types';
|
||||
|
||||
@@ -18,6 +22,15 @@ import { User } from './types';
|
||||
export const getMe = async (): Promise<User> => {
|
||||
const response = await fetchAPI(`users/me/`);
|
||||
|
||||
if (!response.ok && response.status == 401 && canAttemptSilentLogin()) {
|
||||
const currentLocation = window.location.href;
|
||||
attemptSilentLogin(3600);
|
||||
|
||||
while (window.location.href === currentLocation) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
`Couldn't fetch user data: ${response.statusText}`,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { gotoLogin } from '@/features/auth';
|
||||
|
||||
const SILENT_LOGIN_RETRY_KEY = 'silent-login-retry';
|
||||
|
||||
const isRetryAllowed = () => {
|
||||
const lastRetryDate = localStorage.getItem(SILENT_LOGIN_RETRY_KEY);
|
||||
if (!lastRetryDate) {
|
||||
return true;
|
||||
}
|
||||
const now = new Date();
|
||||
return now.getTime() > Number(lastRetryDate);
|
||||
};
|
||||
|
||||
const setNextRetryTime = (retryIntervalInSeconds: number) => {
|
||||
const now = new Date();
|
||||
const nextRetryTime = now.getTime() + retryIntervalInSeconds * 1000;
|
||||
localStorage.setItem(SILENT_LOGIN_RETRY_KEY, String(nextRetryTime));
|
||||
};
|
||||
|
||||
const initiateSilentLogin = () => {
|
||||
const currentPath = window.location.pathname;
|
||||
gotoLogin(currentPath, true);
|
||||
};
|
||||
|
||||
export const canAttemptSilentLogin = () => {
|
||||
return isRetryAllowed();
|
||||
};
|
||||
|
||||
export const attemptSilentLogin = (retryIntervalInSeconds: number) => {
|
||||
if (!isRetryAllowed()) {
|
||||
return;
|
||||
}
|
||||
setNextRetryTime(retryIntervalInSeconds);
|
||||
initiateSilentLogin();
|
||||
};
|
||||
@@ -1,10 +1,11 @@
|
||||
import { backendUrl } from '@/api';
|
||||
import { terminateCrispSession } from '@/services/Crisp';
|
||||
|
||||
import { LOGIN_URL, LOGOUT_URL } from './conf';
|
||||
|
||||
export const gotoLogin = (returnTo = '/') => {
|
||||
const authenticateUrl = LOGIN_URL + `?returnTo=${backendUrl() + returnTo}`;
|
||||
export const gotoLogin = (returnTo = '/', isSilent = false) => {
|
||||
const authenticateUrl =
|
||||
LOGIN_URL +
|
||||
`?silent=${encodeURIComponent(isSilent)}&returnTo=${window.location.origin + returnTo}`;
|
||||
window.location.replace(authenticateUrl);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user