Fix CLI refresh token functionality + reduce token lifetime to 1d & 14d

for refresh
This commit is contained in:
x032205
2025-06-14 01:31:44 -04:00
parent a73c0c05af
commit de917a5d74
10 changed files with 37 additions and 31 deletions
+2 -2
View File
@@ -101,9 +101,9 @@ const envSchema = z
LOOPS_API_KEY: zpStr(z.string().optional()), LOOPS_API_KEY: zpStr(z.string().optional()),
// jwt options // jwt options
AUTH_SECRET: zpStr(z.string()).default(process.env.JWT_AUTH_SECRET), // for those still using old JWT_AUTH_SECRET AUTH_SECRET: zpStr(z.string()).default(process.env.JWT_AUTH_SECRET), // for those still using old JWT_AUTH_SECRET
JWT_AUTH_LIFETIME: zpStr(z.string().default("10d")), JWT_AUTH_LIFETIME: zpStr(z.string().default("1d")),
JWT_SIGNUP_LIFETIME: zpStr(z.string().default("15m")), JWT_SIGNUP_LIFETIME: zpStr(z.string().default("15m")),
JWT_REFRESH_LIFETIME: zpStr(z.string().default("90d")), JWT_REFRESH_LIFETIME: zpStr(z.string().default("14d")),
JWT_INVITE_LIFETIME: zpStr(z.string().default("1d")), JWT_INVITE_LIFETIME: zpStr(z.string().default("1d")),
JWT_MFA_LIFETIME: zpStr(z.string().default("5m")), JWT_MFA_LIFETIME: zpStr(z.string().default("5m")),
JWT_PROVIDER_AUTH_LIFETIME: zpStr(z.string().default("15m")), JWT_PROVIDER_AUTH_LIFETIME: zpStr(z.string().default("15m")),
@@ -107,7 +107,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
server.addHook("onRequest", async (req) => { server.addHook("onRequest", async (req) => {
const appCfg = getConfig(); const appCfg = getConfig();
if (req.url.includes(".well-known/est") || req.url.includes("/api/v3/auth/")) { if (req.url.includes(".well-known/est") || req.url.includes("/api/v3/auth/") || req.url === "/api/v1/auth/token") {
return; return;
} }
+7 -4
View File
@@ -50,7 +50,8 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
200: z.object({ 200: z.object({
token: z.string(), token: z.string(),
isMfaEnabled: z.boolean(), isMfaEnabled: z.boolean(),
mfaMethod: z.string().optional() mfaMethod: z.string().optional(),
refreshToken: z.string().optional()
}) })
} }
}, },
@@ -101,7 +102,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
maxAge: 0 maxAge: 0
}); });
return { token: tokens.access, isMfaEnabled: false }; return { token: tokens.access, isMfaEnabled: false, refreshToken: tokens.refresh };
} }
}); });
@@ -129,7 +130,8 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
encryptedPrivateKey: z.string(), encryptedPrivateKey: z.string(),
iv: z.string(), iv: z.string(),
tag: z.string(), tag: z.string(),
token: z.string() token: z.string(),
refreshToken: z.string().optional()
}) })
} }
}, },
@@ -172,7 +174,8 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
tag: data.user.tag, tag: data.user.tag,
protectedKey: data.user.protectedKey || null, protectedKey: data.user.protectedKey || null,
protectedKeyIV: data.user.protectedKeyIV || null, protectedKeyIV: data.user.protectedKeyIV || null,
protectedKeyTag: data.user.protectedKeyTag || null protectedKeyTag: data.user.protectedKeyTag || null,
refreshToken: data.token.refresh
} as const; } as const;
} }
}); });
+1 -1
View File
@@ -267,7 +267,7 @@ type GetLoginTwoV2Response struct {
ProtectedKey string `json:"protectedKey"` ProtectedKey string `json:"protectedKey"`
ProtectedKeyIV string `json:"protectedKeyIV"` ProtectedKeyIV string `json:"protectedKeyIV"`
ProtectedKeyTag string `json:"protectedKeyTag"` ProtectedKeyTag string `json:"protectedKeyTag"`
RefreshToken string `json:"RefreshToken"` RefreshToken string `json:"refreshToken"`
} }
type VerifyMfaTokenRequest struct { type VerifyMfaTokenRequest struct {
+2 -1
View File
@@ -111,7 +111,7 @@ var loginCmd = &cobra.Command{
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{ infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL, SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT, UserAgent: api.USER_AGENT,
AutoTokenRefresh: false, AutoTokenRefresh: true,
CustomHeaders: customHeaders, CustomHeaders: customHeaders,
}) })
@@ -438,6 +438,7 @@ func cliDefaultLogin(userCredentialsToBeStored *models.UserCredentials) {
userCredentialsToBeStored.Email = email userCredentialsToBeStored.Email = email
userCredentialsToBeStored.PrivateKey = string(decryptedPrivateKey) userCredentialsToBeStored.PrivateKey = string(decryptedPrivateKey)
userCredentialsToBeStored.JTWToken = newJwtToken userCredentialsToBeStored.JTWToken = newJwtToken
userCredentialsToBeStored.RefreshToken = loginTwoResponse.RefreshToken
} }
func init() { func init() {
+1 -1
View File
@@ -6,7 +6,7 @@ type UserCredentials struct {
Email string `json:"email"` Email string `json:"email"`
PrivateKey string `json:"privateKey"` PrivateKey string `json:"privateKey"`
JTWToken string `json:"JTWToken"` JTWToken string `json:"JTWToken"`
RefreshToken string `json:"RefreshToken"` RefreshToken string `json:"refreshToken"`
} }
// The file struct for Infisical config file // The file struct for Infisical config file
+8 -12
View File
@@ -94,19 +94,15 @@ func GetCurrentLoggedInUserDetails(setConfigVariables bool) (LoggedInUserDetails
SetHeader("Accept", "application/json") SetHeader("Accept", "application/json")
isAuthenticated := api.CallIsAuthenticated(httpClient) isAuthenticated := api.CallIsAuthenticated(httpClient)
// TODO: add refresh token if !isAuthenticated {
// if !isAuthenticated { accessTokenResponse, refreshErr := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken)
// accessTokenResponse, err := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken) if refreshErr == nil && accessTokenResponse.Token != "" {
// if err == nil && accessTokenResponse.Token != "" { isAuthenticated = true
// isAuthenticated = true userCreds.JTWToken = accessTokenResponse.Token
// userCreds.JTWToken = accessTokenResponse.Token }
// } }
// }
// err = StoreUserCredsInKeyRing(&userCreds) _ = StoreUserCredsInKeyRing(&userCreds)
// if err != nil {
// log.Debug().Msg("unable to store your user credentials with new access token")
// }
if !isAuthenticated { if !isAuthenticated {
return LoggedInUserDetails{ return LoggedInUserDetails{
+1
View File
@@ -73,6 +73,7 @@ export const selectOrganization = async (data: {
}) => { }) => {
const { data: res } = await apiRequest.post<{ const { data: res } = await apiRequest.post<{
token: string; token: string;
refreshToken: string;
isMfaEnabled: boolean; isMfaEnabled: boolean;
mfaMethod?: MfaMethod; mfaMethod?: MfaMethod;
}>("/api/v3/auth/select-organization", data); }>("/api/v3/auth/select-organization", data);
@@ -76,7 +76,9 @@ export const PasswordStep = ({
// case: organization ID is present from the provider auth token -- select the org and use the new jwt token in the CLI, then navigate to the org // case: organization ID is present from the provider auth token -- select the org and use the new jwt token in the CLI, then navigate to the org
if (organizationId) { if (organizationId) {
const finishWithOrgWorkflow = async () => { const finishWithOrgWorkflow = async () => {
const { token, isMfaEnabled, mfaMethod } = await selectOrganization({ organizationId }); const { token, isMfaEnabled, mfaMethod, refreshToken } = await selectOrganization({
organizationId
});
if (isMfaEnabled) { if (isMfaEnabled) {
SecurityClient.setMfaToken(token); SecurityClient.setMfaToken(token);
@@ -94,10 +96,11 @@ export const PasswordStep = ({
const payload = { const payload = {
privateKey, privateKey,
email, email,
JTWToken: token JTWToken: token,
refreshToken
}; };
await instance.post(cliUrl, payload).catch(() => { await instance.post(cliUrl, payload).catch(() => {
// if error happens to communicate we set the token with an expiry in sessino storage // if error happens to communicate we set the token with an expiry in session storage
// the cli-redirect page has logic to show this to user and ask them to paste it in terminal // the cli-redirect page has logic to show this to user and ask them to paste it in terminal
sessionStorage.setItem( sessionStorage.setItem(
SessionStorageKeys.CLI_TERMINAL_TOKEN, SessionStorageKeys.CLI_TERMINAL_TOKEN,
@@ -187,7 +190,7 @@ export const PasswordStep = ({
// case: organization ID is present from the provider auth token -- select the org and use the new jwt token in the CLI, then navigate to the org // case: organization ID is present from the provider auth token -- select the org and use the new jwt token in the CLI, then navigate to the org
if (organizationId) { if (organizationId) {
const finishWithOrgWorkflow = async () => { const finishWithOrgWorkflow = async () => {
const { token, isMfaEnabled, mfaMethod } = await selectOrganization({ const { token, isMfaEnabled, mfaMethod, refreshToken } = await selectOrganization({
organizationId organizationId
}); });
@@ -206,10 +209,11 @@ export const PasswordStep = ({
const instance = axios.create(); const instance = axios.create();
const payload = { const payload = {
...isCliLoginSuccessful.loginResponse, ...isCliLoginSuccessful.loginResponse,
JTWToken: token JTWToken: token,
refreshToken
}; };
await instance.post(cliUrl, payload).catch(() => { await instance.post(cliUrl, payload).catch(() => {
// if error happens to communicate we set the token with an expiry in sessino storage // if error happens to communicate we set the token with an expiry in session storage
// the cli-redirect page has logic to show this to user and ask them to paste it in terminal // the cli-redirect page has logic to show this to user and ask them to paste it in terminal
sessionStorage.setItem( sessionStorage.setItem(
SessionStorageKeys.CLI_TERMINAL_TOKEN, SessionStorageKeys.CLI_TERMINAL_TOKEN,
@@ -112,7 +112,7 @@ export const SelectOrganizationSection = () => {
return; return;
} }
const { token, isMfaEnabled, mfaMethod } = await selectOrg const { token, isMfaEnabled, mfaMethod, refreshToken } = await selectOrg
.mutateAsync({ .mutateAsync({
organizationId: organization.id, organizationId: organization.id,
userAgent: callbackPort ? UserAgentType.CLI : undefined userAgent: callbackPort ? UserAgentType.CLI : undefined
@@ -151,13 +151,14 @@ export const SelectOrganizationSection = () => {
const payload = { const payload = {
JTWToken: token, JTWToken: token,
email: user?.email, email: user?.email,
privateKey privateKey,
refreshToken
} as IsCliLoginSuccessful["loginResponse"]; } as IsCliLoginSuccessful["loginResponse"];
// send request to server endpoint // send request to server endpoint
const instance = axios.create(); const instance = axios.create();
await instance.post(`http://127.0.0.1:${callbackPort}/`, payload).catch(() => { await instance.post(`http://127.0.0.1:${callbackPort}/`, payload).catch(() => {
// if error happens to communicate we set the token with an expiry in sessino storage // if error happens to communicate we set the token with an expiry in session storage
// the cli-redirect page has logic to show this to user and ask them to paste it in terminal // the cli-redirect page has logic to show this to user and ask them to paste it in terminal
sessionStorage.setItem( sessionStorage.setItem(
SessionStorageKeys.CLI_TERMINAL_TOKEN, SessionStorageKeys.CLI_TERMINAL_TOKEN,