Default scopes omit offline_access (fixes #10)
This commit is contained in:
@@ -2,6 +2,16 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [1.0.5] - 2026-05-XX
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
- Redirect to `/login` when there is no refresh token.
|
||||
- Default scopes omit `offline_access`.
|
||||
|
||||
## [1.0.4] - 2026-05-11
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "stalwart-webui",
|
||||
"private": true,
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"description": "Stalwart WebUI",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -8,10 +8,10 @@ import { Navigate, useLocation } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/authStore';
|
||||
|
||||
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const accessToken = useAuthStore((s) => s.accessToken);
|
||||
const authenticated = useAuthStore((s) => s.isAuthenticated());
|
||||
const bypassToken = import.meta.env.VITE_ACCESS_TOKEN;
|
||||
const location = useLocation();
|
||||
if (!accessToken && !bypassToken) {
|
||||
if (!authenticated && !bypassToken) {
|
||||
const originalPath = location.pathname + location.search;
|
||||
return <Navigate to="/login" replace state={{ from: originalPath }} />;
|
||||
}
|
||||
|
||||
+7
-1
@@ -107,13 +107,19 @@ export async function apiFetch(path: string, options?: RequestInit): Promise<Res
|
||||
|
||||
let response = await makeRequest();
|
||||
|
||||
if (response.status === 401 && useAuthStore.getState().refreshToken) {
|
||||
if (response.status === 401) {
|
||||
if (useAuthStore.getState().refreshToken) {
|
||||
try {
|
||||
await refreshAccessToken();
|
||||
response = await makeRequest();
|
||||
} catch {
|
||||
throw new ApiError(401, 'Unauthorized', null);
|
||||
}
|
||||
} else {
|
||||
useAuthStore.getState().logout();
|
||||
window.location.href = `${getBasePath()}/login`;
|
||||
throw new ApiError(401, 'Unauthorized', null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -125,8 +125,7 @@ function getRedirectUri(): string {
|
||||
}
|
||||
|
||||
export async function startAuthFlow(username: string, returnUrl?: string | null): Promise<void> {
|
||||
const { authorization_endpoint, token_endpoint, end_session_endpoint, scopes_supported } =
|
||||
await discover(username);
|
||||
const { authorization_endpoint, token_endpoint, end_session_endpoint, scopes_supported } = await discover(username);
|
||||
|
||||
const codeVerifier = generateCodeVerifier();
|
||||
const { challenge: codeChallenge, method: codeChallengeMethod } = await generateCodeChallenge(codeVerifier);
|
||||
@@ -167,7 +166,7 @@ export async function startAuthFlow(username: string, returnUrl?: string | null)
|
||||
if (SCOPES && SCOPES.length > 0) {
|
||||
scope = SCOPES;
|
||||
} else if (scopes_supported?.includes('openid')) {
|
||||
scope = ['openid', 'email', 'profile'].filter((s) => scopes_supported.includes(s)).join(' ');
|
||||
scope = ['openid', 'email', 'profile', 'offline_access'].filter((s) => scopes_supported.includes(s)).join(' ');
|
||||
} else {
|
||||
scope = '';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user