@@ -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 ) {
@@ -897,6 +1012,58 @@ func RefreshToken(c *gin.Context) {
8971012 })
8981013}
8991014
1015+ // GetUser returns the current user information
1016+ func GetUser (c * gin.Context ) {
1017+ userId := c .GetString ("userId" )
1018+
1019+ ctx := c .Request .Context ()
1020+
1021+ if userId == "" {
1022+ c .JSON (http .StatusUnauthorized , gin.H {
1023+ "error" : "Not authenticated" ,
1024+ })
1025+ return
1026+ }
1027+
1028+ user := & User {
1029+ ID : & userId ,
1030+ }
1031+
1032+ ownTeam , err := user .getOwnTeam (ctx )
1033+ if err != nil {
1034+ msg := "Unable to get user's team"
1035+ fmt .Println (msg , err )
1036+ c .JSON (http .StatusInternalServerError , gin.H {
1037+ "error" : msg ,
1038+ })
1039+ return
1040+ }
1041+
1042+ err = user .getUserDetails (ctx )
1043+
1044+ if err != nil {
1045+ msg := "Unable to get user details"
1046+ fmt .Println (msg , err )
1047+ c .JSON (http .StatusInternalServerError , gin.H {
1048+ "error" : msg ,
1049+ })
1050+ return
1051+ }
1052+
1053+ c .JSON (http .StatusOK , gin.H {
1054+ "user" : gin.H {
1055+ "id" : userId ,
1056+ "own_team_id" : ownTeam .ID ,
1057+ "name" : user .Name ,
1058+ "email" : user .Email ,
1059+ "confirmed_at" : user .ConfirmedAt ,
1060+ "last_sign_in_at" : user .LastSignInAt ,
1061+ "created_at" : user .CreatedAt ,
1062+ "updated_at" : user .UpdatedAt ,
1063+ },
1064+ })
1065+ }
1066+
9001067// GetSession returns the current session information
9011068func GetAuthSession (c * gin.Context ) {
9021069 userId := c .GetString ("userId" )
0 commit comments