RevokeAPIKey marks an API key as revoked in the database, preventing its future use. The function updates the is_revoked flag to true and sets the revoked_at timestamp. It also invalidates the cache entry for the revoked key to ensure immediate effect. Only the owner of the API key can revoke it. P
(ctx context.Context, id, ownerID string)
| 202 | // - error: Returns ErrAPIKeyNotFound if the key doesn't exist or doesn't belong to the owner, |
| 203 | // or other database errors if the update operation fails. |
| 204 | func (s *Datasource) RevokeAPIKey(ctx context.Context, id, ownerID string) error { |
| 205 | // First, get the API key to retrieve its hashed key for cache invalidation |
| 206 | getQuery := ` |
| 207 | SELECT key |
| 208 | FROM ledgerforge.api_keys |
| 209 | WHERE api_key_id = $1 AND owner_id = $2 |
| 210 | ` |
| 211 | |
| 212 | var hashedKey string |
| 213 | err := s.Conn.QueryRowContext(ctx, getQuery, id, ownerID).Scan(&hashedKey) |
| 214 | if err == sql.ErrNoRows { |
| 215 | return ErrAPIKeyNotFound |
| 216 | } |
| 217 | if err != nil { |
| 218 | return err |
| 219 | } |
| 220 | |
| 221 | // Update the API key to mark it as revoked |
| 222 | updateQuery := ` |
| 223 | UPDATE ledgerforge.api_keys |
| 224 | SET is_revoked = true, revoked_at = $1 |
| 225 | WHERE api_key_id = $2 AND owner_id = $3 |
| 226 | ` |
| 227 | |
| 228 | result, err := s.Conn.ExecContext(ctx, updateQuery, time.Now(), id, ownerID) |
| 229 | if err != nil { |
| 230 | return err |
| 231 | } |
| 232 | |
| 233 | rows, err := result.RowsAffected() |
| 234 | if err != nil { |
| 235 | return err |
| 236 | } |
| 237 | |
| 238 | if rows == 0 { |
| 239 | return ErrAPIKeyNotFound |
| 240 | } |
| 241 | |
| 242 | // Invalidate the cache entry for this API key |
| 243 | // Note: We need to get the key_prefix to invalidate the correct cache entry |
| 244 | getPrefixQuery := `SELECT key_prefix FROM ledgerforge.api_keys WHERE api_key_id = $1` |
| 245 | var keyPrefix sql.NullString |
| 246 | _ = s.Conn.QueryRowContext(ctx, getPrefixQuery, id).Scan(&keyPrefix) |
| 247 | |
| 248 | if keyPrefix.Valid && s.Cache != nil { |
| 249 | cacheKey := getAPIKeyCacheKey(keyPrefix.String) |
| 250 | err = s.Cache.Delete(ctx, cacheKey) |
| 251 | if err != nil { |
| 252 | // Log the error, but don't fail the revocation |
| 253 | logrus.WithError(err).Warn("failed to invalidate API key cache") |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | return nil |
| 258 | } |
| 259 | |
| 260 | // UpdateLastUsed updates the last_used_at timestamp for an API key to the current time. |
| 261 | // This function is typically called during authentication to track API key usage patterns. |