@@ -56,6 +56,27 @@ func extractToken(c *gin.Context) (token string) {
5656	return 
5757}
5858
59+ // extractMcpKey extracts the MCP key 
60+ // from the Authorization header. 
61+ func  extractMcpKey (c  * gin.Context ) (token  string ) {
62+ 	authHeader  :=  c .GetHeader ("Authorization" )
63+ 	splitToken  :=  strings .Split (authHeader , "Bearer " )
64+ 
65+ 	if  len (splitToken ) !=  2  {
66+ 		c .AbortWithStatus (http .StatusUnauthorized )
67+ 		return 
68+ 	}
69+ 
70+ 	token  =  strings .TrimSpace (splitToken [1 ])
71+ 
72+ 	if  token  ==  ""  {
73+ 		c .AbortWithStatus ((http .StatusUnauthorized ))
74+ 		return 
75+ 	}
76+ 
77+ 	return 
78+ }
79+ 
5980// extractRefreshToken extracts the refresh token 
6081// from the cookie or Authorization header 
6182func  extractRefreshToken (c  * gin.Context ) (token  string ) {
@@ -145,6 +166,100 @@ func ValidateAccessToken() gin.HandlerFunc {
145166	}
146167}
147168
169+ // ValidateMcpKey validates the Measure MCP key. 
170+ func  ValidateMcpKey () gin.HandlerFunc  {
171+ 	return  func (c  * gin.Context ) {
172+ 		key  :=  extractMcpKey (c )
173+ 
174+ 		userId , teamId , err  :=  DecodeMcpKey (key )
175+ 		if  err  !=  nil  {
176+ 			c .AbortWithStatusJSON (http .StatusUnauthorized , gin.H {
177+ 				"error" : "invalid MCP key" ,
178+ 			})
179+ 			return 
180+ 		}
181+ 
182+ 		if  userId  ==  nil  {
183+ 			msg  :=  "no user found for this MCP key" 
184+ 			fmt .Println (msg )
185+ 			c .AbortWithStatusJSON (http .StatusNotFound , gin.H {"error" : msg })
186+ 			return 
187+ 		}
188+ 
189+ 		if  teamId  ==  nil  {
190+ 			msg  :=  "no team found for this MCP key" 
191+ 			fmt .Println (msg )
192+ 			c .AbortWithStatusJSON (http .StatusNotFound , gin.H {"error" : msg })
193+ 			return 
194+ 		}
195+ 
196+ 		c .Set ("userId" , userId .String ())
197+ 		c .Set ("teamId" , teamId .String ())
198+ 		c .Next ()
199+ 	}
200+ }
201+ 
202+ // ValidateAccessTokenOrMcpKey validates the Measure access token or MCP key. If either one succeeds, the request is allowed. 
203+ func  ValidateAccessTokenOrMcpKey () gin.HandlerFunc  {
204+ 	return  func (c  * gin.Context ) {
205+ 		token  :=  extractToken (c )
206+ 
207+ 		// Try access token validation first 
208+ 		accessToken , err  :=  jwt .Parse (token , func (token  * jwt.Token ) (any , error ) {
209+ 			if  _ , ok  :=  token .Method .(* jwt.SigningMethodHMAC ); ! ok  {
210+ 				err  :=  fmt .Errorf ("unexpected signing method: %v" , token .Header ["alg" ])
211+ 				return  nil , err 
212+ 			}
213+ 
214+ 			return  server .Server .Config .AccessTokenSecret , nil 
215+ 		})
216+ 
217+ 		// If access token is valid, use it 
218+ 		if  err  ==  nil  {
219+ 			if  claims , ok  :=  accessToken .Claims .(jwt.MapClaims ); ok  {
220+ 				sessionId  :=  claims ["jti" ]
221+ 				c .Set ("sessionId" , sessionId )
222+ 
223+ 				userId  :=  claims ["sub" ]
224+ 				c .Set ("userId" , userId )
225+ 
226+ 				c .Next ()
227+ 				return 
228+ 			}
229+ 		}
230+ 
231+ 		// Access token failed, try MCP key 
232+ 		key  :=  extractMcpKey (c )
233+ 		userId , teamId , err  :=  DecodeMcpKey (key )
234+ 		if  err  !=  nil  {
235+ 			// Both validations failed 
236+ 			fmt .Println ("both access token and MCP key validation failed" )
237+ 			c .AbortWithStatusJSON (http .StatusUnauthorized , gin.H {
238+ 				"error" : "invalid access token or MCP key" ,
239+ 			})
240+ 			return 
241+ 		}
242+ 
243+ 		if  userId  ==  nil  {
244+ 			msg  :=  "no user found for this MCP key" 
245+ 			fmt .Println (msg )
246+ 			c .AbortWithStatusJSON (http .StatusNotFound , gin.H {"error" : msg })
247+ 			return 
248+ 		}
249+ 
250+ 		if  teamId  ==  nil  {
251+ 			msg  :=  "no team found for this MCP key" 
252+ 			fmt .Println (msg )
253+ 			c .AbortWithStatusJSON (http .StatusNotFound , gin.H {"error" : msg })
254+ 			return 
255+ 		}
256+ 
257+ 		c .Set ("userId" , userId .String ())
258+ 		c .Set ("teamId" , teamId .String ())
259+ 		c .Next ()
260+ 	}
261+ }
262+ 
148263// ValidateRefreshToken validates the Measure refresh token. 
149264func  ValidateRefreshToken () gin.HandlerFunc  {
150265	return  func (c  * gin.Context ) {
@@ -967,6 +1082,58 @@ func RefreshToken(c *gin.Context) {
9671082	})
9681083}
9691084
1085+ // GetUser returns the current user information 
1086+ func  GetUser (c  * gin.Context ) {
1087+ 	userId  :=  c .GetString ("userId" )
1088+ 
1089+ 	ctx  :=  c .Request .Context ()
1090+ 
1091+ 	if  userId  ==  ""  {
1092+ 		c .JSON (http .StatusUnauthorized , gin.H {
1093+ 			"error" : "Not authenticated" ,
1094+ 		})
1095+ 		return 
1096+ 	}
1097+ 
1098+ 	user  :=  & User {
1099+ 		ID : & userId ,
1100+ 	}
1101+ 
1102+ 	ownTeam , err  :=  user .getOwnTeam (ctx )
1103+ 	if  err  !=  nil  {
1104+ 		msg  :=  "Unable to get user's team" 
1105+ 		fmt .Println (msg , err )
1106+ 		c .JSON (http .StatusInternalServerError , gin.H {
1107+ 			"error" : msg ,
1108+ 		})
1109+ 		return 
1110+ 	}
1111+ 
1112+ 	err  =  user .getUserDetails (ctx )
1113+ 
1114+ 	if  err  !=  nil  {
1115+ 		msg  :=  "Unable to get user details" 
1116+ 		fmt .Println (msg , err )
1117+ 		c .JSON (http .StatusInternalServerError , gin.H {
1118+ 			"error" : msg ,
1119+ 		})
1120+ 		return 
1121+ 	}
1122+ 
1123+ 	c .JSON (http .StatusOK , gin.H {
1124+ 		"user" : gin.H {
1125+ 			"id" :              userId ,
1126+ 			"own_team_id" :     ownTeam .ID ,
1127+ 			"name" :            user .Name ,
1128+ 			"email" :           user .Email ,
1129+ 			"confirmed_at" :    user .ConfirmedAt ,
1130+ 			"last_sign_in_at" : user .LastSignInAt ,
1131+ 			"created_at" :      user .CreatedAt ,
1132+ 			"updated_at" :      user .UpdatedAt ,
1133+ 		},
1134+ 	})
1135+ }
1136+ 
9701137// GetSession returns the current session information 
9711138func  GetAuthSession (c  * gin.Context ) {
9721139	userId  :=  c .GetString ("userId" )
0 commit comments