@@ -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 (c , 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 (c , 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