1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
/**
* Authentication via API introspection
*
* This validates OAuth tokens and API keys by calling the main Supermemory API,
*/
export interface AuthUser {
userId: string
apiKey: string
email?: string
name?: string
}
/**
* Check if a token is an API key (starts with "sm_")
*/
export function isApiKey(token: string): boolean {
return token.startsWith("sm_")
}
/**
* Validate API key by calling the main API's session endpoint.
* Returns user info if the API key is valid.
*/
export async function validateApiKey(
apiKey: string,
apiUrl: string,
): Promise<AuthUser | null> {
try {
const sessionResponse = await fetch(`${apiUrl}/v3/session`, {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
},
})
if (!sessionResponse.ok) {
const responseText = await sessionResponse.text()
const status = sessionResponse.status
if (status === 401) {
console.error("API key validation failed: Invalid or expired API key")
} else if (status === 403) {
console.error(
"API key validation failed: User is blocked or access forbidden",
responseText,
)
} else if (status === 429) {
console.error("API key validation failed: Rate limit exceeded")
} else if (status >= 500) {
console.error(
"API key validation failed: Server error",
status,
responseText,
)
} else {
console.error("API key validation failed:", status, responseText)
}
return null
}
const sessionData = (await sessionResponse.json()) as {
user?: {
id?: string
email?: string
name?: string
}
session?: unknown
org?: unknown
error?: string
} | null
if (!sessionData?.user?.id) {
console.error("Missing user.id in session response:", sessionData)
return null
}
console.log("API key validated for user:", sessionData.user.id)
return {
userId: sessionData.user.id,
apiKey: apiKey,
email: sessionData.user.email,
name: sessionData.user.name,
}
} catch (error) {
console.error("API key validation error:", error)
return null
}
}
/**
* Validate OAuth token by calling the main API's MCP session endpoint.
* The main API validates the token via better-auth and returns user info + API key.
*/
export async function validateOAuthToken(
token: string,
apiUrl: string,
): Promise<AuthUser | null> {
try {
const sessionResponse = await fetch(`${apiUrl}/v3/mcp/session-with-key`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
})
if (!sessionResponse.ok) {
const responseText = await sessionResponse.text()
const status = sessionResponse.status
if (status === 401) {
console.error("Token validation failed: Invalid or expired token")
} else if (status === 403) {
console.error(
"Token validation failed: User is blocked or access forbidden",
responseText,
)
} else if (status === 429) {
console.error("Token validation failed: Rate limit exceeded")
} else if (status >= 500) {
console.error(
"Token validation failed: Server error",
status,
responseText,
)
} else {
console.error("Token validation failed:", status, responseText)
}
return null
}
const sessionData = (await sessionResponse.json()) as {
userId?: string
apiKey?: string
email?: string
name?: string
error?: string
} | null
if (!sessionData?.userId || !sessionData?.apiKey) {
console.error(
"Missing userId or apiKey in session response:",
sessionData,
)
return null
}
console.log("OAuth validated, got API key for user:", sessionData.userId)
return {
userId: sessionData.userId,
apiKey: sessionData.apiKey,
email: sessionData.email,
name: sessionData.name,
}
} catch (error) {
console.error("Token validation error:", error)
return null
}
}
|