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  }