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/).
|
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
|
## [1.0.4] - 2026-05-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "stalwart-webui",
|
"name": "stalwart-webui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"description": "Stalwart WebUI",
|
"description": "Stalwart WebUI",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import { Navigate, useLocation } from 'react-router-dom';
|
|||||||
import { useAuthStore } from '@/stores/authStore';
|
import { useAuthStore } from '@/stores/authStore';
|
||||||
|
|
||||||
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
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 bypassToken = import.meta.env.VITE_ACCESS_TOKEN;
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
if (!accessToken && !bypassToken) {
|
if (!authenticated && !bypassToken) {
|
||||||
const originalPath = location.pathname + location.search;
|
const originalPath = location.pathname + location.search;
|
||||||
return <Navigate to="/login" replace state={{ from: originalPath }} />;
|
return <Navigate to="/login" replace state={{ from: originalPath }} />;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-5
@@ -107,11 +107,17 @@ export async function apiFetch(path: string, options?: RequestInit): Promise<Res
|
|||||||
|
|
||||||
let response = await makeRequest();
|
let response = await makeRequest();
|
||||||
|
|
||||||
if (response.status === 401 && useAuthStore.getState().refreshToken) {
|
if (response.status === 401) {
|
||||||
try {
|
if (useAuthStore.getState().refreshToken) {
|
||||||
await refreshAccessToken();
|
try {
|
||||||
response = await makeRequest();
|
await refreshAccessToken();
|
||||||
} catch {
|
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);
|
throw new ApiError(401, 'Unauthorized', null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,8 +125,7 @@ function getRedirectUri(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startAuthFlow(username: string, returnUrl?: string | null): Promise<void> {
|
export async function startAuthFlow(username: string, returnUrl?: string | null): Promise<void> {
|
||||||
const { authorization_endpoint, token_endpoint, end_session_endpoint, scopes_supported } =
|
const { authorization_endpoint, token_endpoint, end_session_endpoint, scopes_supported } = await discover(username);
|
||||||
await discover(username);
|
|
||||||
|
|
||||||
const codeVerifier = generateCodeVerifier();
|
const codeVerifier = generateCodeVerifier();
|
||||||
const { challenge: codeChallenge, method: codeChallengeMethod } = await generateCodeChallenge(codeVerifier);
|
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) {
|
if (SCOPES && SCOPES.length > 0) {
|
||||||
scope = SCOPES;
|
scope = SCOPES;
|
||||||
} else if (scopes_supported?.includes('openid')) {
|
} 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 {
|
} else {
|
||||||
scope = '';
|
scope = '';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user