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