Skip to content

Add Personal Access Token API Filters

What does this MR do and why?

Fixes #362248 (closed)

Adds a new set of filters for personal access token (PAT) API.

The filters are:

GET /personal_access_tokens?revoked=true
GET /personal_access_tokens?created_before=2022-01-01T00:00:00
GET /personal_access_tokens?created_after=2022-01-01T00:00:00
GET /personal_access_tokens?scopes=api,read_user
GET /personal_access_tokens?search=name
GET /personal_access_tokens?last_used_before=2022-01-01T00:00:00
GET /personal_access_tokens?last_used_after=2022-01-01T00:00:00
GET /personal_access_tokens?active=false

How to set up and validate locally

  1. Create one or multiple PAT token
  2. Set a value for a token property that matches your filter. E.g. if you are looking for revoked tokens - set one token revoked and another you leave valid
  3. Run the following commands
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?revoked=true
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?created_before=2022-01-01T00:00:00
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?created_after=2022-01-01T00:00:00
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?scopes=api,read_user
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?search=name
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?last_used_before=2022-01-01T00:00:00
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?last_used_after=2022-01-01T00:00:00
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?active=false
  1. You can also merge the filters
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/personal_access_tokens?active=false&last_used_before=2022-01-01T00:00:00

DB Review

Queries

Filter Query
active https://explain.depesz.com/s/arLB
created_after https://explain.depesz.com/s/hxu8
created_before https://explain.depesz.com/s/gbw9
last_used_after https://explain.depesz.com/s/5jdg
last_used_before https://explain.depesz.com/s/7N4d
scopes https://explain.depesz.com/s/HRVt9
search https://explain.depesz.com/s/kdp8
revoked https://explain.depesz.com/s/EAf1
created_at & id https://explain.depesz.com/s/d2PQ
created_before & search https://explain.depesz.com/s/DUXA
created_before & user_id https://explain.depesz.com/s/D3BJ
created_before & search & scopes https://explain.depesz.com/s/yfoR
created_before & search & scopes & last_used_after https://explain.depesz.com/s/CLNP
created_before & search & scopes & revoked https://explain.depesz.com/s/8x8T

🛠 with at Siemens

Migrations up

> rails db:migrate
main: == 20220530100052 AddPersonalAccessTokensNameGinIndex: migrating ==============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:personal_access_tokens, :name, {:name=>"index_personal_access_tokens_on_name_trigram", :using=>:gin, :opclass=>{:name=>:gin_trgm_ops}, :algorithm=>:concurrently})
main:    -> 0.0400s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0024s
main: -- add_index(:personal_access_tokens, :name, {:name=>"index_personal_access_tokens_on_name_trigram", :using=>:gin, :opclass=>{:name=>:gin_trgm_ops}, :algorithm=>:concurrently})
main:    -> 0.0817s
main: -- execute("RESET statement_timeout")
main:    -> 0.0016s
main: == 20220530100052 AddPersonalAccessTokensNameGinIndex: migrated (0.1562s) =====

main: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: migrating ============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:personal_access_tokens, [:user_id, :created_at], {:name=>"index_personal_access_tokens_on_created_at", :algorithm=>:concurrently})
main:    -> 0.0114s
main: -- add_index(:personal_access_tokens, [:user_id, :created_at], {:name=>"index_personal_access_tokens_on_created_at", :algorithm=>:concurrently})
main:    -> 0.0107s
main: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: migrated (0.0315s) ===

main: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: migrating ===========
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:personal_access_tokens, [:user_id, :last_used_at], {:name=>"index_personal_access_tokens_on_last_used_at", :algorithm=>:concurrently})
main:    -> 0.0058s
main: -- add_index(:personal_access_tokens, [:user_id, :last_used_at], {:name=>"index_personal_access_tokens_on_last_used_at", :algorithm=>:concurrently})
main:    -> 0.0024s
main: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: migrated (0.0146s) ==

main: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: migrating ============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- index_exists?(:personal_access_tokens, :scopes, {:name=>"index_personal_access_tokens_on_scopes_trigram", :using=>:gin, :opclass=>{:scopes=>:gin_trgm_ops}, :algorithm=>:concurrently})
main:    -> 0.0250s
main: -- add_index(:personal_access_tokens, :scopes, {:name=>"index_personal_access_tokens_on_scopes_trigram", :using=>:gin, :opclass=>{:scopes=>:gin_trgm_ops}, :algorithm=>:concurrently})
main:    -> 0.0120s
main: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: migrated (0.0428s) ===

ci: == 20220530100052 AddPersonalAccessTokensNameGinIndex: migrating ==============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:personal_access_tokens, :name, {:name=>"index_personal_access_tokens_on_name_trigram", :using=>:gin, :opclass=>{:name=>:gin_trgm_ops}, :algorithm=>:concurrently})
ci:    -> 0.0420s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0018s
ci: -- add_index(:personal_access_tokens, :name, {:name=>"index_personal_access_tokens_on_name_trigram", :using=>:gin, :opclass=>{:name=>:gin_trgm_ops}, :algorithm=>:concurrently})
ci:    -> 0.0248s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0039s
ci: == 20220530100052 AddPersonalAccessTokensNameGinIndex: migrated (0.0869s) =====

ci: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: migrating ============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:personal_access_tokens, [:user_id, :created_at], {:name=>"index_personal_access_tokens_on_created_at", :algorithm=>:concurrently})
ci:    -> 0.0126s
ci: -- add_index(:personal_access_tokens, [:user_id, :created_at], {:name=>"index_personal_access_tokens_on_created_at", :algorithm=>:concurrently})
ci:    -> 0.0050s
ci: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: migrated (0.0323s) ===

ci: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: migrating ===========
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:personal_access_tokens, [:user_id, :last_used_at], {:name=>"index_personal_access_tokens_on_last_used_at", :algorithm=>:concurrently})
ci:    -> 0.0911s
ci: -- add_index(:personal_access_tokens, [:user_id, :last_used_at], {:name=>"index_personal_access_tokens_on_last_used_at", :algorithm=>:concurrently})
ci:    -> 0.0070s
ci: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: migrated (0.1266s) ==

ci: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: migrating ============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- index_exists?(:personal_access_tokens, :scopes, {:name=>"index_personal_access_tokens_on_scopes_trigram", :using=>:gin, :opclass=>{:scopes=>:gin_trgm_ops}, :algorithm=>:concurrently})
ci:    -> 0.0123s
ci: -- add_index(:personal_access_tokens, :scopes, {:name=>"index_personal_access_tokens_on_scopes_trigram", :using=>:gin, :opclass=>{:scopes=>:gin_trgm_ops}, :algorithm=>:concurrently})
ci:    -> 0.0035s
ci: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: migrated (0.1074s) ===

Migration down

> rails db:migrate:down:main VERSION=20220531180051 
main: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: reverting ============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:personal_access_tokens)
main:    -> 0.0312s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0017s
main: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_scopes_trigram"})
main:    -> 0.0359s
main: -- execute("RESET statement_timeout")
main:    -> 0.0007s
main: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: reverted (0.0886s) ===

> rails db:migrate:down:main VERSION=20220530131122 
main: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: reverting ===========
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:personal_access_tokens)
main:    -> 0.0892s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0022s
main: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_last_used_at"})
main:    -> 0.0081s
main: -- execute("RESET statement_timeout")
main:    -> 0.0024s
main: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: reverted (0.1297s) ==

> rails db:migrate:down:main VERSION=20220530130446  
main: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: reverting ============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:personal_access_tokens)
main:    -> 0.0144s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0004s
main: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_created_at"})
main:    -> 0.0057s
main: -- execute("RESET statement_timeout")
main:    -> 0.0004s
main: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: reverted (0.0312s) ===

> rails db:migrate:down:main VERSION=20220530100052 
main: == 20220530100052 AddPersonalAccessTokensNameGinIndex: reverting ==============
main: -- transaction_open?()
main:    -> 0.0000s
main: -- indexes(:personal_access_tokens)
main:    -> 0.0183s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0008s
main: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_name_trigram"})
main:    -> 0.0068s
main: -- execute("RESET statement_timeout")
main:    -> 0.0013s
main: == 20220530100052 AddPersonalAccessTokensNameGinIndex: reverted (0.0437s) =====

> rails db:migrate:down:ci VERSION=20220531180051 
ci: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: reverting ============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- indexes(:personal_access_tokens)
ci:    -> 0.0100s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0004s
ci: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_scopes_trigram"})
ci:    -> 0.0068s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0006s
ci: == 20220531180051 AddPersonalAccessTokensScopesGinIndex: reverted (0.0278s) ===

> rails db:migrate:down:ci VERSION=20220530131122 
ci: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: reverting ===========
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- indexes(:personal_access_tokens)
ci:    -> 0.0116s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0004s
ci: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_last_used_at"})
ci:    -> 0.0054s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0007s
ci: == 20220530131122 AddPersonalAccessTokensLastUsedAtIndex: reverted (0.0265s) ==

> rails db:migrate:down:ci VERSION=20220530130446 
ci: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: reverting ============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- indexes(:personal_access_tokens)
ci:    -> 0.0116s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0005s
ci: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_created_at"})
ci:    -> 0.0032s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0007s
ci: == 20220530130446 AddPersonalAccessTokensCreatedAtIndex: reverted (0.0256s) ===

> rails db:migrate:down:ci VERSION=20220530100052 
ci: == 20220530100052 AddPersonalAccessTokensNameGinIndex: reverting ==============
ci: -- transaction_open?()
ci:    -> 0.0000s
ci: -- indexes(:personal_access_tokens)
ci:    -> 0.0104s
ci: -- execute("SET statement_timeout TO 0")
ci:    -> 0.0004s
ci: -- remove_index(:personal_access_tokens, {:algorithm=>:concurrently, :name=>"index_personal_access_tokens_on_name_trigram"})
ci:    -> 0.0040s
ci: -- execute("RESET statement_timeout")
ci:    -> 0.0005s
ci: == 20220530100052 AddPersonalAccessTokensNameGinIndex: reverted (0.0242s) =====

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Andreas Deicha

Merge request reports