Include user information and token expiration in authentication responses

Updated the `Token` schema to include `user` data and `expires_in` field. Adjusted backend `auth_service.py` to populate these fields while generating tokens. Replaced `getCurrentUserInfo` with `getCurrentUserProfile` in the frontend and disabled ESLint for generated files to suppress warnings.
This commit is contained in:
2025-11-02 04:36:29 +01:00
parent 0b0d1d2b06
commit e25b010b57
15 changed files with 37 additions and 48 deletions

2
backend/app/schemas/users.py Normal file → Executable file
View File

@@ -86,6 +86,8 @@ class Token(BaseModel):
access_token: str access_token: str
refresh_token: Optional[str] = None refresh_token: Optional[str] = None
token_type: str = "bearer" token_type: str = "bearer"
user: "UserResponse" # Forward reference since UserResponse is defined above
expires_in: Optional[int] = None # Token expiration in seconds
class TokenPayload(BaseModel): class TokenPayload(BaseModel):

View File

@@ -15,7 +15,7 @@ from app.core.auth import (
TokenInvalidError TokenInvalidError
) )
from app.models.user import User from app.models.user import User
from app.schemas.users import Token, UserCreate from app.schemas.users import Token, UserCreate, UserResponse
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -118,7 +118,7 @@ class AuthService:
user: User to create tokens for user: User to create tokens for
Returns: Returns:
Token object with access and refresh tokens Token object with access and refresh tokens and user info
""" """
# Generate claims # Generate claims
claims = { claims = {
@@ -137,9 +137,14 @@ class AuthService:
subject=str(user.id) subject=str(user.id)
) )
# Convert User model to UserResponse schema
user_response = UserResponse.model_validate(user)
return Token( return Token(
access_token=access_token, access_token=access_token,
refresh_token=refresh_token refresh_token=refresh_token,
user=user_response,
expires_in=86400 # 24 hours in seconds (matching ACCESS_TOKEN_EXPIRE_MINUTES)
) )
@staticmethod @staticmethod

View File

@@ -1,5 +0,0 @@
{
"root": true,
"ignorePatterns": ["*"],
"rules": {}
}

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
import { type ClientOptions, type Config, createClient, createConfig } from './client'; import { type ClientOptions, type Config, createClient, createConfig } from './client';
import type { ClientOptions as ClientOptions2 } from './types.gen'; import type { ClientOptions as ClientOptions2 } from './types.gen';

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
export type { Auth } from '../core/auth.gen'; export type { Auth } from '../core/auth.gen';
export type { QuerySerializerOptions } from '../core/bodySerializer.gen'; export type { QuerySerializerOptions } from '../core/bodySerializer.gen';

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
export type AuthToken = string | undefined; export type AuthToken = string | undefined;

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
type Slot = 'body' | 'headers' | 'path' | 'query'; type Slot = 'body' | 'headers' | 'path' | 'query';

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
interface SerializeOptions<T> interface SerializeOptions<T>
extends SerializePrimitiveOptions, extends SerializePrimitiveOptions,

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
/** /**
* JSON-friendly union that mirrors what Pinia Colada can hash. * JSON-friendly union that mirrors what Pinia Colada can hash.

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
import type { Auth, AuthToken } from './auth.gen'; import type { Auth, AuthToken } from './auth.gen';
import type { import type {

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; import type { BodySerializer, QuerySerializer } from './bodySerializer.gen';
import { import {

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
export type * from './types.gen'; export type * from './types.gen';
export * from './sdk.gen'; export * from './sdk.gen';

View File

@@ -1,8 +1,9 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
import { type Client, type Options as Options2, type TDataShape, urlSearchParamsBodySerializer } from './client'; import { type Client, type Options as Options2, type TDataShape, urlSearchParamsBodySerializer } from './client';
import { client } from './client.gen'; import { client } from './client.gen';
import type { AdminActivateUserData, AdminActivateUserErrors, AdminActivateUserResponses, AdminAddOrganizationMemberData, AdminAddOrganizationMemberErrors, AdminAddOrganizationMemberResponses, AdminBulkUserActionData, AdminBulkUserActionErrors, AdminBulkUserActionResponses, AdminCreateOrganizationData, AdminCreateOrganizationErrors, AdminCreateOrganizationResponses, AdminCreateUserData, AdminCreateUserErrors, AdminCreateUserResponses, AdminDeactivateUserData, AdminDeactivateUserErrors, AdminDeactivateUserResponses, AdminDeleteOrganizationData, AdminDeleteOrganizationErrors, AdminDeleteOrganizationResponses, AdminDeleteUserData, AdminDeleteUserErrors, AdminDeleteUserResponses, AdminGetOrganizationData, AdminGetOrganizationErrors, AdminGetOrganizationResponses, AdminGetUserData, AdminGetUserErrors, AdminGetUserResponses, AdminListOrganizationMembersData, AdminListOrganizationMembersErrors, AdminListOrganizationMembersResponses, AdminListOrganizationsData, AdminListOrganizationsErrors, AdminListOrganizationsResponses, AdminListUsersData, AdminListUsersErrors, AdminListUsersResponses, AdminRemoveOrganizationMemberData, AdminRemoveOrganizationMemberErrors, AdminRemoveOrganizationMemberResponses, AdminUpdateOrganizationData, AdminUpdateOrganizationErrors, AdminUpdateOrganizationResponses, AdminUpdateUserData, AdminUpdateUserErrors, AdminUpdateUserResponses, ChangeCurrentUserPasswordData, ChangeCurrentUserPasswordErrors, ChangeCurrentUserPasswordResponses, CleanupExpiredSessionsData, CleanupExpiredSessionsResponses, ConfirmPasswordResetData, ConfirmPasswordResetErrors, ConfirmPasswordResetResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, GetCurrentUserInfoData, GetCurrentUserInfoResponses, GetCurrentUserProfileData, GetCurrentUserProfileResponses, GetMyOrganizationsData, GetMyOrganizationsErrors, GetMyOrganizationsResponses, GetOrganizationData, GetOrganizationErrors, GetOrganizationMembersData, GetOrganizationMembersErrors, GetOrganizationMembersResponses, GetOrganizationResponses, GetUserByIdData, GetUserByIdErrors, GetUserByIdResponses, HealthCheckData, HealthCheckResponses, ListMySessionsData, ListMySessionsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, LoginData, LoginErrors, LoginOauthData, LoginOauthErrors, LoginOauthResponses, LoginResponses, LogoutAllData, LogoutAllResponses, LogoutData, LogoutErrors, LogoutResponses, RefreshTokenData, RefreshTokenErrors, RefreshTokenResponses, RegisterData, RegisterErrors, RegisterResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, RevokeSessionData, RevokeSessionErrors, RevokeSessionResponses, RootGetData, RootGetResponses, UpdateCurrentUserData, UpdateCurrentUserErrors, UpdateCurrentUserResponses, UpdateOrganizationData, UpdateOrganizationErrors, UpdateOrganizationResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses } from './types.gen'; import type { AdminActivateUserData, AdminActivateUserErrors, AdminActivateUserResponses, AdminAddOrganizationMemberData, AdminAddOrganizationMemberErrors, AdminAddOrganizationMemberResponses, AdminBulkUserActionData, AdminBulkUserActionErrors, AdminBulkUserActionResponses, AdminCreateOrganizationData, AdminCreateOrganizationErrors, AdminCreateOrganizationResponses, AdminCreateUserData, AdminCreateUserErrors, AdminCreateUserResponses, AdminDeactivateUserData, AdminDeactivateUserErrors, AdminDeactivateUserResponses, AdminDeleteOrganizationData, AdminDeleteOrganizationErrors, AdminDeleteOrganizationResponses, AdminDeleteUserData, AdminDeleteUserErrors, AdminDeleteUserResponses, AdminGetOrganizationData, AdminGetOrganizationErrors, AdminGetOrganizationResponses, AdminGetUserData, AdminGetUserErrors, AdminGetUserResponses, AdminListOrganizationMembersData, AdminListOrganizationMembersErrors, AdminListOrganizationMembersResponses, AdminListOrganizationsData, AdminListOrganizationsErrors, AdminListOrganizationsResponses, AdminListUsersData, AdminListUsersErrors, AdminListUsersResponses, AdminRemoveOrganizationMemberData, AdminRemoveOrganizationMemberErrors, AdminRemoveOrganizationMemberResponses, AdminUpdateOrganizationData, AdminUpdateOrganizationErrors, AdminUpdateOrganizationResponses, AdminUpdateUserData, AdminUpdateUserErrors, AdminUpdateUserResponses, ChangeCurrentUserPasswordData, ChangeCurrentUserPasswordErrors, ChangeCurrentUserPasswordResponses, CleanupExpiredSessionsData, CleanupExpiredSessionsResponses, ConfirmPasswordResetData, ConfirmPasswordResetErrors, ConfirmPasswordResetResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, GetCurrentUserProfileData, GetCurrentUserProfileResponses, GetMyOrganizationsData, GetMyOrganizationsErrors, GetMyOrganizationsResponses, GetOrganizationData, GetOrganizationErrors, GetOrganizationMembersData, GetOrganizationMembersErrors, GetOrganizationMembersResponses, GetOrganizationResponses, GetUserByIdData, GetUserByIdErrors, GetUserByIdResponses, HealthCheckData, HealthCheckResponses, ListMySessionsData, ListMySessionsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, LoginData, LoginErrors, LoginOauthData, LoginOauthErrors, LoginOauthResponses, LoginResponses, LogoutAllData, LogoutAllResponses, LogoutData, LogoutErrors, LogoutResponses, RefreshTokenData, RefreshTokenErrors, RefreshTokenResponses, RegisterData, RegisterErrors, RegisterResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, RevokeSessionData, RevokeSessionErrors, RevokeSessionResponses, RootGetData, RootGetResponses, UpdateCurrentUserData, UpdateCurrentUserErrors, UpdateCurrentUserResponses, UpdateOrganizationData, UpdateOrganizationErrors, UpdateOrganizationResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses } from './types.gen';
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options2<TData, ThrowOnError> & { export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options2<TData, ThrowOnError> & {
/** /**
@@ -129,27 +130,6 @@ export const refreshToken = <ThrowOnError extends boolean = false>(options: Opti
}); });
}; };
/**
* Get Current User Info
*
* Get current user information.
*
* Requires authentication.
*/
export const getCurrentUserInfo = <ThrowOnError extends boolean = false>(options?: Options<GetCurrentUserInfoData, ThrowOnError>) => {
return (options?.client ?? client).get<GetCurrentUserInfoResponses, unknown, ThrowOnError>({
responseType: 'json',
security: [
{
scheme: 'bearer',
type: 'http'
}
],
url: '/api/v1/auth/me',
...options
});
};
/** /**
* Request Password Reset * Request Password Reset
* *

View File

@@ -1,4 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
/* eslint-disable */
export type ClientOptions = { export type ClientOptions = {
baseURL: `${string}://${string}` | (string & {}); baseURL: `${string}://${string}` | (string & {});
@@ -560,6 +561,11 @@ export type Token = {
* Token Type * Token Type
*/ */
token_type?: string; token_type?: string;
user: UserResponse;
/**
* Expires In
*/
expires_in?: number | null;
}; };
/** /**
@@ -650,6 +656,10 @@ export type UserUpdate = {
* Phone Number * Phone Number
*/ */
phone_number?: string | null; phone_number?: string | null;
/**
* Password
*/
password?: string | null;
/** /**
* Preferences * Preferences
*/ */
@@ -660,6 +670,10 @@ export type UserUpdate = {
* Is Active * Is Active
*/ */
is_active?: boolean | null; is_active?: boolean | null;
/**
* Is Superuser
*/
is_superuser?: boolean | null;
}; };
/** /**
@@ -810,22 +824,6 @@ export type RefreshTokenResponses = {
export type RefreshTokenResponse = RefreshTokenResponses[keyof RefreshTokenResponses]; export type RefreshTokenResponse = RefreshTokenResponses[keyof RefreshTokenResponses];
export type GetCurrentUserInfoData = {
body?: never;
path?: never;
query?: never;
url: '/api/v1/auth/me';
};
export type GetCurrentUserInfoResponses = {
/**
* Successful Response
*/
200: UserResponse;
};
export type GetCurrentUserInfoResponse = GetCurrentUserInfoResponses[keyof GetCurrentUserInfoResponses];
export type RequestPasswordResetData = { export type RequestPasswordResetData = {
body: PasswordResetRequest; body: PasswordResetRequest;
path?: never; path?: never;

4
frontend/src/lib/api/hooks/useAuth.ts Normal file → Executable file
View File

@@ -15,7 +15,7 @@ import {
register, register,
logout, logout,
logoutAll, logoutAll,
getCurrentUserInfo, getCurrentUserProfile,
requestPasswordReset, requestPasswordReset,
confirmPasswordReset, confirmPasswordReset,
changeCurrentUserPassword, changeCurrentUserPassword,
@@ -55,7 +55,7 @@ export function useMe() {
const query = useQuery({ const query = useQuery({
queryKey: authKeys.me, queryKey: authKeys.me,
queryFn: async (): Promise<User> => { queryFn: async (): Promise<User> => {
const response = await getCurrentUserInfo({ const response = await getCurrentUserProfile({
throwOnError: true, throwOnError: true,
}); });
return response.data as User; return response.data as User;