diff --git a/jwt/service/jwt_token_service.go b/jwt/service/jwt_token_service.go index 4c5e0bca..b3240f21 100644 --- a/jwt/service/jwt_token_service.go +++ b/jwt/service/jwt_token_service.go @@ -188,7 +188,7 @@ func (ts *JWTokenService) Parse(s string) (model.JWToken, error) { } // ValidateTokenString parses token and validates it. -func (ts *JWTokenService) ValidateTokenString(tstr string, v jv.Validator, tokenType string) (model.JWToken, error) { +func (ts *JWTokenService) ValidateTokenString(tstr string, v jv.Validator, tokenType model.TokenType) (model.JWToken, error) { token, err := ts.Parse(tstr) if err != nil { return model.JWToken{}, err diff --git a/jwt/service/jwt_token_service_test.go b/jwt/service/jwt_token_service_test.go index 37c14164..15259a01 100644 --- a/jwt/service/jwt_token_service_test.go +++ b/jwt/service/jwt_token_service_test.go @@ -97,3 +97,31 @@ func TestNewToken(t *testing.T) { _, err = tokenService.Parse(tokenString) require.NoError(t, err) } + +func TestNewResetToken(t *testing.T) { + tokenService := createTokenService(t) + + user := model.User{ + ID: "12345566", + Username: "username", + Email: "username@gmailc.om", + } + token, err := tokenService.NewToken(model.TokenTypeReset, user, nil, nil, nil) + assert.NoError(t, err) + + ts, err := tokenService.SignToken(token) + assert.NoError(t, err) + + pt, err := tokenService.Parse(ts) + require.NoError(t, err) + assert.Equal(t, model.TokenTypeReset, pt.Type()) + + // check we have empty audience + aud, err := pt.Claims.GetAudience() + assert.NoError(t, err) + assert.Empty(t, aud) + + // check we have empty email and username + assert.NotContains(t, pt.Payload(), "email") + assert.NotContains(t, pt.Payload(), "username") +} diff --git a/model/token.go b/model/token.go index f4aebf7a..94126360 100644 --- a/model/token.go +++ b/model/token.go @@ -77,7 +77,7 @@ func (t *JWToken) UserID() string { } // Payload returns token payload. -func (t *JWToken) Payload() map[string]interface{} { +func (t *JWToken) Payload() map[string]any { claims, ok := t.Claims.(*Claims) if !ok { return nil @@ -86,12 +86,12 @@ func (t *JWToken) Payload() map[string]interface{} { } // Type returns token type. -func (t *JWToken) Type() string { +func (t *JWToken) Type() TokenType { claims, ok := t.Claims.(*Claims) if !ok { return "" } - return claims.Type + return TokenType(claims.Type) } // ExpiresAt standard token claim diff --git a/web/management/invite.go b/web/management/invite.go index 330d4828..a61fb47c 100644 --- a/web/management/invite.go +++ b/web/management/invite.go @@ -6,8 +6,18 @@ import ( "github.com/madappgang/identifo/v2/l" "github.com/madappgang/identifo/v2/model" + "golang.org/x/exp/maps" ) +// InviteRequest is a request for invite. +type InvitationTokenRequest struct { + Email string `json:"email"` + AppID string `json:"app_id"` + Roles map[string]any `json:"roles"` + CallbackURL string `json:"callback"` + Data map[string]any `json:"data"` +} + func (ar *Router) getInviteToken(w http.ResponseWriter, r *http.Request) { locale := r.Header.Get("Accept-Language") @@ -33,7 +43,20 @@ func (ar *Router) getInviteToken(w http.ResponseWriter, r *http.Request) { return } - inviteToken, err := ar.server.Services().Token.NewInviteToken(d.Email, d.Role, d.ApplicationID, d.Data) + u := model.User{ + ID: model.NewUserID.String(), // token sub is new user ID + Email: d.Email, + } + aud := []string{} + if len(d.AppID) > 0 { + aud = append(aud, d.AppID) + } + fields := model.UserFieldsetMap[model.UserFieldsetInviteToken] + maps.Copy(d.Data, d.Roles) + if len(d.CallbackURL) > 0 { + d.Data["callback"] = d.CallbackURL + } + inviteToken, err := ar.server.Services().Token.NewToken(model.TokenTypeInvite, u, aud, fields, d.Data) if err != nil { ar.Error(w, locale, http.StatusInternalServerError, l.ErrorTokenInviteCreateError, err) return diff --git a/web/management/models.go b/web/management/models.go index a320bd54..09d1f3e3 100644 --- a/web/management/models.go +++ b/web/management/models.go @@ -1,13 +1,5 @@ package management -type InvitationTokenRequest struct { - Email string `json:"email"` - ApplicationID string `json:"application_id"` - Role string `json:"access_role"` - CallbackURL string `json:"callback_url"` - Data map[string]interface{} `json:"data"` -} - type ResetPasswordTokenRequest struct { Email string `json:"email"` } diff --git a/web/management/reset_password.go b/web/management/reset_password.go index 991666a9..8c5ab839 100644 --- a/web/management/reset_password.go +++ b/web/management/reset_password.go @@ -37,7 +37,8 @@ func (ar *Router) getResetPasswordToken(w http.ResponseWriter, r *http.Request) return } - resetToken, err := ar.server.Services().Token.NewResetToken(user.ID) + // reset token has no auditory, fields from user or any other payload + resetToken, err := ar.server.Services().Token.NewToken(model.TokenTypeReset, user, nil, nil, nil) if err != nil { ar.Error(w, locale, http.StatusInternalServerError, l.ErrorTokenUnableToCreateResetTokenError, err) return