Skip to content

Commit f5946de

Browse files
authored
fix: Update Hypermode api key reading for modus local dev (#805)
1 parent 38ace7c commit f5946de

File tree

5 files changed

+30
-48
lines changed

5 files changed

+30
-48
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
# Change Log
44

5+
## 2025-04-01 - Runtime 0.17.8
6+
7+
- fix: Update Hypermode api key reading for modus local dev [#805](https://github.com/hypermodeinc/modus/pull/805)
8+
9+
## 2025-04-01 - CLI 0.17.2
10+
11+
- fix: Update Hypermode api key reading for modus local dev [#805](https://github.com/hypermodeinc/modus/pull/805)
12+
513
## 2025-03-28 - Runtime 0.17.7
614

715
- feat: support new Dgraph connection string format [#803](https://github.com/hypermodeinc/modus/pull/803)

cli/src/commands/dev/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ export default class DevCommand extends BaseCommand {
164164
...process.env,
165165
MODUS_ENV: "dev",
166166
HYP_EMAIL: hypSettings.email,
167-
HYP_JWT: hypSettings.jwt,
168-
HYP_ORG_ID: hypSettings.orgId,
167+
HYP_API_KEY: hypSettings.apiKey,
168+
HYP_WORKSPACE_ID: hypSettings.workspaceId,
169169
};
170170

171171
// Spawn the runtime child process

cli/src/util/hypermode.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import chalk from "chalk";
1414

1515
type HypSettings = {
1616
email?: string;
17-
jwt?: string;
18-
orgId?: string;
17+
apiKey?: string;
18+
workspaceId?: string;
1919
};
2020

2121
export async function readHypermodeSettings(): Promise<HypSettings> {
@@ -28,8 +28,8 @@ export async function readHypermodeSettings(): Promise<HypSettings> {
2828
const settings = JSON.parse(await fs.readFile(path, "utf-8"));
2929
return {
3030
email: settings.HYP_EMAIL,
31-
jwt: settings.HYP_JWT,
32-
orgId: settings.HYP_ORG_ID,
31+
apiKey: settings.HYP_API_KEY,
32+
workspaceId: settings.HYP_WORKSPACE_ID,
3333
};
3434
} catch (e) {
3535
console.warn(chalk.yellow("Error reading " + path), e);

runtime/models/models.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,17 @@ func PostToModelEndpoint[TResult any](ctx context.Context, model *manifest.Model
9393
var empty TResult
9494
var httpe *utils.HttpError
9595
if errors.As(err, &httpe) {
96-
if app.IsDevEnvironment() && httpe.StatusCode == http.StatusNotFound {
97-
return empty, fmt.Errorf("model %s is not available in the local dev environment", model.SourceModel)
96+
switch httpe.StatusCode {
97+
case http.StatusNotFound:
98+
if app.IsDevEnvironment() {
99+
return empty, fmt.Errorf("model %s is not available in the local dev environment", model.SourceModel)
100+
}
101+
case http.StatusUnauthorized:
102+
return empty, fmt.Errorf("invalid or expired API key. Please use `hyp login` to create a new API key")
103+
case http.StatusForbidden:
104+
return empty, fmt.Errorf("API key is disabled or usage limit exceeded")
105+
case http.StatusTooManyRequests:
106+
return empty, fmt.Errorf("rate limit exceeded")
98107
}
99108
}
100109

runtime/secrets/secrets.go

+5-40
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ import (
1616
"net/http"
1717
"os"
1818
"regexp"
19-
"time"
2019

2120
"github.com/fatih/color"
22-
"github.com/golang-jwt/jwt/v5"
2321
"github.com/hypermodeinc/modus/lib/manifest"
2422
"github.com/hypermodeinc/modus/runtime/logger"
2523
"github.com/hypermodeinc/modus/runtime/utils"
@@ -94,57 +92,24 @@ func ApplySecretsToHttpRequest(ctx context.Context, connection *manifest.HTTPCon
9492

9593
func ApplyAuthToLocalHypermodeModelRequest(ctx context.Context, connection manifest.ConnectionInfo, req *http.Request) error {
9694

97-
jwt := os.Getenv("HYP_JWT")
98-
orgId := os.Getenv("HYP_ORG_ID")
95+
apiKey := os.Getenv("HYP_API_KEY")
96+
workspaceId := os.Getenv("HYP_WORKSPACE_ID")
9997

10098
warningColor := color.New(color.FgHiYellow, color.Bold)
10199

102-
if jwt == "" || orgId == "" {
100+
if apiKey == "" || workspaceId == "" {
103101
fmt.Fprintln(os.Stderr)
104102
warningColor.Fprintln(os.Stderr, "Warning: Local authentication not found. Please login using `hyp login`")
105103
fmt.Fprintln(os.Stderr)
106104
return errLocalAuthFailed
107105
}
108106

109-
isExpired, err := checkJWTExpiration(jwt)
110-
if err != nil {
111-
return err
112-
}
113-
if isExpired {
114-
fmt.Fprintln(os.Stderr)
115-
warningColor.Fprintln(os.Stderr, "Warning: Local authentication expired. Please login using `hyp login`")
116-
fmt.Fprintln(os.Stderr)
117-
return errLocalAuthFailed
118-
}
119-
120-
req.Header.Set("Authorization", "Bearer "+jwt)
121-
req.Header.Set("HYP-ORG-ID", orgId)
107+
req.Header.Set("Authorization", "Bearer "+apiKey)
108+
req.Header.Set("HYP-WORKSPACE-ID", workspaceId)
122109

123110
return nil
124111
}
125112

126-
// checkJWTExpiration checks if the JWT has expired based on the 'exp' claim.
127-
func checkJWTExpiration(tokenString string) (bool, error) {
128-
p := jwt.Parser{}
129-
token, _, err := p.ParseUnverified(tokenString, jwt.MapClaims{})
130-
if err != nil {
131-
return false, fmt.Errorf("failed to parse: %w", err)
132-
}
133-
134-
claims, ok := token.Claims.(jwt.MapClaims)
135-
if !ok {
136-
return false, fmt.Errorf("failed to extract claims from JWT")
137-
}
138-
139-
exp, ok := claims["exp"].(float64)
140-
if !ok {
141-
return false, fmt.Errorf("exp claim is missing or not a number")
142-
}
143-
144-
expirationTime := time.Unix(int64(exp), 0)
145-
return time.Now().After(expirationTime), nil
146-
}
147-
148113
// ApplySecretsToString evaluates the given string and replaces any placeholders
149114
// present in the string with their secret values for the given connection.
150115
func ApplySecretsToString(ctx context.Context, connection manifest.ConnectionInfo, str string) (string, error) {

0 commit comments

Comments
 (0)