mirror of
https://github.com/DeBrosOfficial/network-ts-sdk.git
synced 2025-12-11 01:58:49 +00:00
Refactor AuthClient and HttpClient to allow coexistence of API key and JWT; implement logoutUser method to clear JWT while preserving API key, enhancing user logout functionality. Improve header management in HttpClient for database operations and add debug logging for request headers.
This commit is contained in:
parent
dcf8efe428
commit
76bb82d4f8
@ -28,14 +28,14 @@ export class AuthClient {
|
||||
|
||||
setApiKey(apiKey: string) {
|
||||
this.currentApiKey = apiKey;
|
||||
this.currentJwt = undefined;
|
||||
// Don't clear JWT - it will be cleared explicitly on logout
|
||||
this.httpClient.setApiKey(apiKey);
|
||||
this.storage.set("apiKey", apiKey);
|
||||
}
|
||||
|
||||
setJwt(jwt: string) {
|
||||
this.currentJwt = jwt;
|
||||
this.currentApiKey = undefined;
|
||||
// Don't clear API key - keep it as fallback for after logout
|
||||
this.httpClient.setJwt(jwt);
|
||||
this.storage.set("jwt", jwt);
|
||||
}
|
||||
@ -62,6 +62,51 @@ export class AuthClient {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user and clear JWT, but preserve API key
|
||||
* Use this for user logout in apps where API key is app-level credential
|
||||
*/
|
||||
async logoutUser(): Promise<void> {
|
||||
// Attempt server-side logout if using JWT
|
||||
if (this.currentJwt) {
|
||||
try {
|
||||
await this.httpClient.post("/v1/auth/logout", { all: true });
|
||||
} catch (error) {
|
||||
// Log warning but don't fail - local cleanup is more important
|
||||
console.warn(
|
||||
"Server-side logout failed, continuing with local cleanup:",
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear JWT only, preserve API key
|
||||
this.currentJwt = undefined;
|
||||
this.httpClient.setJwt(undefined);
|
||||
await this.storage.set("jwt", ""); // Clear JWT from storage
|
||||
|
||||
// Ensure API key is loaded and set as active auth method
|
||||
if (!this.currentApiKey) {
|
||||
// Try to load from storage
|
||||
const storedApiKey = await this.storage.get("apiKey");
|
||||
if (storedApiKey) {
|
||||
this.currentApiKey = storedApiKey;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore API key as the active auth method
|
||||
if (this.currentApiKey) {
|
||||
this.httpClient.setApiKey(this.currentApiKey);
|
||||
console.log("[Auth] API key restored after user logout");
|
||||
} else {
|
||||
console.warn("[Auth] No API key available after logout");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Full logout - clears both JWT and API key
|
||||
* Use this to completely reset authentication state
|
||||
*/
|
||||
async logout(): Promise<void> {
|
||||
// Only attempt server-side logout if using JWT
|
||||
// API keys don't support server-side logout with all=true
|
||||
|
||||
@ -27,20 +27,53 @@ export class HttpClient {
|
||||
|
||||
setApiKey(apiKey?: string) {
|
||||
this.apiKey = apiKey;
|
||||
this.jwt = undefined;
|
||||
// Don't clear JWT - allow both to coexist
|
||||
if (typeof console !== "undefined") {
|
||||
console.log(
|
||||
"[HttpClient] API key set:",
|
||||
!!apiKey,
|
||||
"JWT still present:",
|
||||
!!this.jwt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setJwt(jwt?: string) {
|
||||
this.jwt = jwt;
|
||||
this.apiKey = undefined;
|
||||
// Don't clear API key - allow both to coexist
|
||||
if (typeof console !== "undefined") {
|
||||
console.log(
|
||||
"[HttpClient] JWT set:",
|
||||
!!jwt,
|
||||
"API key still present:",
|
||||
!!this.apiKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private getAuthHeaders(): Record<string, string> {
|
||||
private getAuthHeaders(path: string): Record<string, string> {
|
||||
const headers: Record<string, string> = {};
|
||||
if (this.jwt) {
|
||||
headers["Authorization"] = `Bearer ${this.jwt}`;
|
||||
} else if (this.apiKey) {
|
||||
headers["X-API-Key"] = this.apiKey;
|
||||
|
||||
// For database operations, ONLY use API key to avoid JWT user context
|
||||
// interfering with namespace-level authorization
|
||||
const isDbOperation = path.includes("/v1/rqlite/");
|
||||
|
||||
if (isDbOperation) {
|
||||
// For database operations: use only API key (preferred for namespace operations)
|
||||
if (this.apiKey) {
|
||||
headers["X-API-Key"] = this.apiKey;
|
||||
} else if (this.jwt) {
|
||||
// Fallback to JWT if no API key
|
||||
headers["Authorization"] = `Bearer ${this.jwt}`;
|
||||
}
|
||||
} else {
|
||||
// For auth/other operations: send both JWT and API key
|
||||
if (this.jwt) {
|
||||
headers["Authorization"] = `Bearer ${this.jwt}`;
|
||||
}
|
||||
if (this.apiKey) {
|
||||
headers["X-API-Key"] = this.apiKey;
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
@ -68,10 +101,29 @@ export class HttpClient {
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
...this.getAuthHeaders(),
|
||||
...this.getAuthHeaders(path),
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
// Debug: Log headers being sent
|
||||
if (
|
||||
typeof console !== "undefined" &&
|
||||
(path.includes("/db/") ||
|
||||
path.includes("/query") ||
|
||||
path.includes("/auth/"))
|
||||
) {
|
||||
console.log("[HttpClient] Request headers for", path, {
|
||||
hasAuth: !!headers["Authorization"],
|
||||
hasApiKey: !!headers["X-API-Key"],
|
||||
authPrefix: headers["Authorization"]
|
||||
? headers["Authorization"].substring(0, 20)
|
||||
: "none",
|
||||
apiKeyPrefix: headers["X-API-Key"]
|
||||
? headers["X-API-Key"].substring(0, 20)
|
||||
: "none",
|
||||
});
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
const requestTimeout = options.timeout ?? this.timeout; // Use override or default
|
||||
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user