| sessionId |
|---|
| session-261005-174554-ealk |
The objective is to dynamically resolve and read the current user’s ID from their JWT authentication token when voting on amendments in src/components/AmendmentCarousel.vue. This replaces hardcoded placeholder user IDs (userId: 1) with genuine authenticated user context to ensure reliable vote attribution and system integrity.
src/utils/auth.ts) to extract payload claims (specifically userId, user_id, or sub) from stored tokens in localStorage (authToken / token).confirm and reject voting methods in src/components/AmendmentCarousel.vue to dynamically retrieve the authenticated user ID.localStorage (authToken and token fallbacks) without third-party runtime bloat.userId, user_id, or sub claims in the token payload.AmendmentCarousel.vue, invoke AmendmentService.voteAmendment with the decoded userId.In src/components/BrandBar.vue, upon Freighter authentication, the token is stored:
const jwt = await AuthService.loginFreighter({ stellarAddress: addr.address });
localStorage.setItem("authToken", jwt.token as string);
In src/components/AmendmentCarousel.vue, confirm and reject currently use a hardcoded userId: 1:
const confirm = async (amendmentId: number) => {
try {
await AmendmentService.voteAmendment({
amendmentId,
inFavor: true,
userId: 1, // Hardcoded placeholder
});
await getAmendments();
} catch (e) {
console.error("Failed to confirm amendment:", e);
}
};
src/utils/auth.ts using native Base64Url decoding (atob / decodeURIComponent) to minimize dependencies while ensuring high performance.localStorage.getItem("authToken") with fallback to localStorage.getItem("token") to ensure seamless compatibility across all authentication paths.src/utils/auth.ts:
export interface JwtPayload {
userId?: number;
user_id?: number;
sub?: string | number;
stellarAddress?: string;
exp?: number;
[key: string]: unknown;
}
export function parseJwt(token: string): JwtPayload | null {
try {
const base64Url = token.split('.')[1];
if (!base64Url) return null;
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(
atob(base64)
.split('')
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
.join('')
);
return JSON.parse(jsonPayload);
} catch {
return null;
}
}
export function getAuthToken(): string | null {
try {
return localStorage.getItem('authToken') || localStorage.getItem('token');
} catch {
return null;
}
}
export function getUserIdFromJwt(): number | undefined {
const token = getAuthToken();
if (!token) return undefined;
const payload = parseJwt(token);
if (!payload) return undefined;
const rawId = payload.userId ?? payload.user_id ?? payload.sub;
const parsedId = Number(rawId);
return !isNaN(parsedId) && parsedId > 0 ? parsedId : undefined;
}
src/components/AmendmentCarousel.vue:
getUserIdFromJwt from ../utils/auth.ts.confirm and reject:
const confirm = async (amendmentId: number) => {
const userId = getUserIdFromJwt();
if (!userId) {
console.error("User is not authenticated or user ID is missing from JWT.");
error.value = "Please connect your wallet to vote on amendments.";
return;
}
try {
await AmendmentService.voteAmendment({
amendmentId,
inFavor: true,
userId,
});
await getAmendments();
} catch (e) {
console.error("Failed to confirm amendment:", e);
}
};
reject(amendmentId: number).src/utils/auth.ts (JWT extraction and user identification helpers)src/components/AmendmentCarousel.vue (Dynamic user ID in voting handlers)authToken contains a valid JWT with userId: 42, confirm and reject pass userId: 42 to AmendmentService.voteAmendment.user_id or sub, the parser accurately extracts the numeric user ID.Create robust utility functions to read and decode JWT claims from localStorage.
src/utils/auth.ts with parseJwt, getAuthToken, and getUserIdFromJwt.userId, user_id, and sub claims, validating numeric output.Update vote submission handlers to use the decoded user ID from the active JWT session.
getUserIdFromJwt in src/components/AmendmentCarousel.vue.confirm to obtain the active user ID and pass it in VoteAmendmentRequest.reject to obtain the active user ID and pass it in VoteAmendmentRequest.