(ctx context.Context, refreshToken string)
| 123 | } |
| 124 | |
| 125 | func (t *tokenAuth) Refresh(ctx context.Context, refreshToken string) (*Token, error) { |
| 126 | token, err := jwt.ParseWithClaims(refreshToken, &Claims{}, func(token *jwt.Token) (interface{}, error) { |
| 127 | return t.secret, nil |
| 128 | }) |
| 129 | |
| 130 | if err != nil { |
| 131 | return nil, fmt.Errorf("invalid refresh token: %w", err) |
| 132 | } |
| 133 | |
| 134 | claims, ok := token.Claims.(*Claims) |
| 135 | if !ok || claims.TokenType != TokenTypeRefresh { |
| 136 | return nil, ErrInvalidRefreshToken |
| 137 | } |
| 138 | |
| 139 | uid, err := t.idEncoder.Decode(claims.Subject, hashid.UserID) |
| 140 | if err != nil { |
| 141 | return nil, ErrUserNotFound |
| 142 | } |
| 143 | |
| 144 | expectedUser, err := t.userClient.GetActiveByID(ctx, uid) |
| 145 | if err != nil { |
| 146 | return nil, ErrUserNotFound |
| 147 | } |
| 148 | |
| 149 | // Check if user changed password or revoked session |
| 150 | expectedHash := t.hashUserState(ctx, expectedUser) |
| 151 | if !bytes.Equal(claims.StateHash, expectedHash[:]) { |
| 152 | return nil, ErrInvalidRefreshToken |
| 153 | } |
| 154 | |
| 155 | // Check if root token is revoked |
| 156 | if claims.RootTokenID == nil { |
| 157 | return nil, ErrInvalidRefreshToken |
| 158 | } |
| 159 | |
| 160 | _, ok = t.kv.Get(fmt.Sprintf("%s%s", RevokeTokenPrefix, claims.RootTokenID.String())) |
| 161 | if ok { |
| 162 | return nil, ErrInvalidRefreshToken |
| 163 | } |
| 164 | |
| 165 | // If token issued for an OAuth client, check if the client is still valid |
| 166 | refreshTTLOverride := time.Duration(0) |
| 167 | if claims.ClientID != "" { |
| 168 | client, err := t.oAuthClient.GetByGUIDWithGrants(ctx, claims.ClientID, expectedUser.ID) |
| 169 | if err != nil || len(client.Edges.Grants) == 0 { |
| 170 | return nil, ErrInvalidRefreshToken |
| 171 | } |
| 172 | |
| 173 | // Consented scopes must be a subset of the client's scopes |
| 174 | if !ValidateScopes(claims.Scopes, client.Edges.Grants[0].Scopes) { |
| 175 | return nil, ErrInvalidRefreshToken |
| 176 | } |
| 177 | |
| 178 | // Update last used at for the grant |
| 179 | if err := t.oAuthClient.UpdateGrantLastUsedAt(ctx, expectedUser.ID, client.ID); err != nil { |
| 180 | return nil, ErrInvalidRefreshToken |
| 181 | } |
| 182 |
nothing calls this directly
no test coverage detected