1
0

feat: add long-lived api tokens (#1085)

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1085
Co-authored-by: konrad <k@knt.li>
Co-committed-by: konrad <k@knt.li>
This commit is contained in:
konrad
2022-02-06 13:18:08 +00:00
parent 2598550e49
commit 1322cb16d7
11 changed files with 51 additions and 8 deletions

View File

@ -38,6 +38,7 @@ const (
// #nosec
ServiceJWTSecret Key = `service.JWTSecret`
ServiceJWTTTL Key = `service.jwtttl`
ServiceJWTTTLLong Key = `service.jwtttllong`
ServiceInterface Key = `service.interface`
ServiceUnixSocket Key = `service.unixsocket`
ServiceUnixSocketMode Key = `service.unixsocketmode`
@ -227,7 +228,8 @@ func InitDefaultConfig() {
// Service
ServiceJWTSecret.setDefault(random)
ServiceJWTTTL.setDefault(259200)
ServiceJWTTTL.setDefault(259200) // 72 hours
ServiceJWTTTLLong.setDefault(2592000) // 30 days
ServiceInterface.setDefault(":3456")
ServiceUnixSocket.setDefault("")
ServiceFrontendurl.setDefault("")

View File

@ -119,7 +119,7 @@ func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context)
func addUserTokenToContext(t *testing.T, user *user.User, c echo.Context) {
// Get the token as a string
token, err := auth.NewUserJWTAuthtoken(user)
token, err := auth.NewUserJWTAuthtoken(user, false)
assert.NoError(t, err)
// We send the string token through the parsing function to get a valid jwt.Token
tken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {

View File

@ -42,8 +42,8 @@ type Token struct {
}
// NewUserAuthTokenResponse creates a new user auth token response from a user object.
func NewUserAuthTokenResponse(u *user.User, c echo.Context) error {
t, err := NewUserJWTAuthtoken(u)
func NewUserAuthTokenResponse(u *user.User, c echo.Context, long bool) error {
t, err := NewUserJWTAuthtoken(u, long)
if err != nil {
return err
}
@ -52,10 +52,13 @@ func NewUserAuthTokenResponse(u *user.User, c echo.Context) error {
}
// NewUserJWTAuthtoken generates and signes a new jwt token for a user. This is a global function to be able to call it from integration tests.
func NewUserJWTAuthtoken(u *user.User) (token string, err error) {
func NewUserJWTAuthtoken(u *user.User, long bool) (token string, err error) {
t := jwt.New(jwt.SigningMethodHS256)
var ttl = time.Duration(config.ServiceJWTTTL.GetInt64())
if long {
ttl = time.Duration(config.ServiceJWTTTLLong.GetInt64())
}
var exp = time.Now().Add(time.Second * ttl).Unix()
// Set claims
@ -68,6 +71,7 @@ func NewUserJWTAuthtoken(u *user.User) (token string, err error) {
claims["name"] = u.Name
claims["emailRemindersEnabled"] = u.EmailRemindersEnabled
claims["isLocalUser"] = u.Issuer == user.IssuerLocal
claims["long"] = long
// Generate encoded token and send it as response.
return t.SignedString([]byte(config.ServiceJWTSecret.GetString()))

View File

@ -198,7 +198,7 @@ func HandleCallback(c echo.Context) error {
}
// Create token
return auth.NewUserAuthTokenResponse(u, c)
return auth.NewUserAuthTokenResponse(u, c, false)
}
func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *user.User, err error) {

View File

@ -102,7 +102,7 @@ func Login(c echo.Context) error {
}
// Create token
return auth.NewUserAuthTokenResponse(user, c)
return auth.NewUserAuthTokenResponse(user, c, u.LongToken)
}
// RenewToken gives a new token to every user with a valid token
@ -156,6 +156,12 @@ func RenewToken(c echo.Context) (err error) {
return handler.HandleHTTPError(err, c)
}
var long bool
lng, has := claims["long"]
if has {
long = lng.(bool)
}
// Create token
return auth.NewUserAuthTokenResponse(user, c)
return auth.NewUserAuthTokenResponse(user, c, long)
}

View File

@ -8847,6 +8847,10 @@ var doc = `{
"user.Login": {
"type": "object",
"properties": {
"long_token": {
"description": "If true, the token returned will be valid a lot longer than default. Useful for \"remember me\" style logins.",
"type": "boolean"
},
"password": {
"description": "The password for the user.",
"type": "string"

View File

@ -8831,6 +8831,10 @@
"user.Login": {
"type": "object",
"properties": {
"long_token": {
"description": "If true, the token returned will be valid a lot longer than default. Useful for \"remember me\" style logins.",
"type": "boolean"
},
"password": {
"description": "The password for the user.",
"type": "string"

View File

@ -1157,6 +1157,10 @@ definitions:
type: object
user.Login:
properties:
long_token:
description: If true, the token returned will be valid a lot longer than default.
Useful for "remember me" style logins.
type: boolean
password:
description: The password for the user.
type: string

View File

@ -44,6 +44,8 @@ type Login struct {
Password string `json:"password"`
// The totp passcode of a user. Only needs to be provided when enabled.
TOTPPasscode string `json:"totp_passcode"`
// If true, the token returned will be valid a lot longer than default. Useful for "remember me" style logins.
LongToken bool `json:"long_token"`
}
type Status int