github.com/resonatecoop/id@v1.1.0-43/oauth/refresh_token.go (about) 1 package oauth 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 "github.com/google/uuid" 9 "github.com/resonatecoop/id/util" 10 "github.com/resonatecoop/user-api/model" 11 ) 12 13 var ( 14 // ErrRefreshTokenNotFound ... 15 ErrRefreshTokenNotFound = errors.New("Refresh token not found") 16 // ErrRefreshTokenExpired ... 17 ErrRefreshTokenExpired = errors.New("Refresh token expired") 18 // ErrRequestedScopeCannotBeGreater ... 19 ErrRequestedScopeCannotBeGreater = errors.New("Requested scope cannot be greater") 20 ) 21 22 // GetOrCreateRefreshToken retrieves an existing refresh token, if expired, 23 // the token gets deleted and new refresh token is created 24 func (s *Service) GetOrCreateRefreshToken(client *model.Client, user *model.User, expiresIn int, scope string) (*model.RefreshToken, error) { 25 ctx := context.Background() 26 // Try to fetch an existing refresh token first 27 refreshToken := new(model.RefreshToken) 28 // query := model.RefreshTokenPreload(s.db).Where("client_id = ?", client.ID) 29 30 var err error 31 32 if user != nil && user.ID != uuid.Nil { 33 err = s.db.NewSelect(). 34 Model(refreshToken). 35 Where("client_id = ?", client.ID). 36 Where("user_id = ?", user.ID). 37 Limit(1). 38 Scan(ctx) 39 } else { 40 err = s.db.NewSelect(). 41 Model(refreshToken). 42 Where("client_id = ?", client.ID). 43 Where("user_id = uuid_nil()"). 44 Limit(1). 45 Scan(ctx) 46 } 47 48 // Check if the token is expired, if found 49 var expired bool 50 if err == nil { 51 expired = time.Now().UTC().After(refreshToken.ExpiresAt) 52 } 53 54 var dberr error 55 // If the refresh token has expired, delete it 56 if expired { 57 _, dberr = s.db.NewDelete(). 58 Model(refreshToken). 59 WherePK(). 60 ForceDelete(). 61 Exec(ctx) 62 // s.db.Unscoped().Delete(refreshToken) 63 } 64 65 if dberr != nil { 66 return nil, dberr 67 } 68 69 // Create a new refresh token if it expired or was not found 70 if expired || (err != nil) { 71 refreshToken = model.NewOauthRefreshToken(client, user, expiresIn, scope) 72 73 _, err = s.db.NewInsert(). 74 Model(refreshToken). 75 Exec(ctx) 76 77 if err != nil { 78 return nil, err 79 } 80 81 refreshToken.Client = client 82 refreshToken.User = user 83 } 84 85 return refreshToken, nil 86 } 87 88 // GetValidRefreshToken returns a valid non expired refresh token 89 func (s *Service) GetValidRefreshToken(token string, client *model.Client) (*model.RefreshToken, error) { 90 ctx := context.Background() 91 // Fetch the refresh token from the database 92 refreshToken := new(model.RefreshToken) 93 94 err := s.db.NewSelect(). 95 Model(refreshToken). 96 Where("client_id = ?", client.ID). 97 Where("token = ?", token). 98 Limit(1). 99 Scan(ctx) 100 101 // Not found 102 if err != nil { 103 return nil, ErrRefreshTokenNotFound 104 } 105 106 // Check the refresh token hasn't expired 107 if time.Now().UTC().After(refreshToken.ExpiresAt) { 108 return nil, ErrRefreshTokenExpired 109 } 110 111 user := new(model.User) 112 113 err = s.db.NewSelect(). 114 Model(user). 115 Where("id = ?", refreshToken.UserID). 116 Limit(1). 117 Scan(ctx) 118 119 // Not found 120 if err != nil { 121 return nil, errors.New("refresh token does not have valid user") 122 } 123 124 refreshToken.Client = client 125 refreshToken.User = user 126 127 return refreshToken, nil 128 } 129 130 // getRefreshTokenScope returns scope for a new refresh token 131 func (s *Service) getRefreshTokenScope(refreshToken *model.RefreshToken, requestedScope string) (string, error) { 132 var ( 133 scope = refreshToken.Scope // default to the scope originally granted by the resource owner 134 err error 135 ) 136 137 // If the scope is specified in the request, get the scope string 138 if requestedScope != "" { 139 scope, err = s.GetScope(requestedScope) 140 if err != nil { 141 return "", err 142 } 143 } 144 145 // Requested scope CANNOT include any scope not originally granted 146 if !util.SpaceDelimitedStringNotGreater(scope, refreshToken.Scope) { 147 return "", ErrRequestedScopeCannotBeGreater 148 } 149 150 return scope, nil 151 }