diff --git a/go.mod b/go.mod index ac2555e..2a29abd 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,40 @@ module github.com/0xsequence/authcontrol go 1.23.2 require ( - github.com/go-chi/chi/v5 v5.1.0 + github.com/go-chi/chi/v5 v5.2.2 + github.com/go-chi/httplog/v3 v3.2.2 github.com/go-chi/jwtauth/v5 v5.3.3 + github.com/go-chi/metrics v0.1.0 github.com/go-chi/traceid v0.2.0 github.com/go-chi/transport v0.4.0 github.com/lestrrat-go/jwx/v2 v2.1.3 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/segmentio/asm v1.2.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/sys v0.30.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3d73fe1..57fb7e3 100644 --- a/go.sum +++ b/go.sum @@ -1,28 +1,39 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/httplog/v3 v3.2.2 h1:G0oYv3YYcikNjijArHFUlqfR78cQNh9fGT43i6StqVc= +github.com/go-chi/httplog/v3 v3.2.2/go.mod h1:N/J1l5l1fozUrqIVuT8Z/HzNeSy8TF2EFyokPLe6y2w= github.com/go-chi/jwtauth/v5 v5.3.3 h1:50Uzmacu35/ZP9ER2Ht6SazwPsnLQ9LRJy6zTZJpHEo= github.com/go-chi/jwtauth/v5 v5.3.3/go.mod h1:O4QvPRuZLZghl9WvfVaON+ARfGzpD2PBX/QY5vUz7aQ= +github.com/go-chi/metrics v0.1.0 h1:lLE2/43HtiPXrEIRFv6rbXarnta+E7O6C5WUE8Bv9Ho= +github.com/go-chi/metrics v0.1.0/go.mod h1:eRYNXI3HzvDiyHgGaIDTTWEGNT4xnecgs1af7J75XCw= github.com/go-chi/traceid v0.2.0 h1:M4SVlzbnq6zfNCOvi8LwLFGugY04El+hS8njO0Pwml4= github.com/go-chi/traceid v0.2.0/go.mod h1:XFfEEYZjqgML4ySh+wYBU29eqJkc2um7oEzgIc63e74= github.com/go-chi/transport v0.4.0 h1:wKkHHapDbijGz7sGicEqyQIj6KD/LV5+R7H8QrZQMco= github.com/go-chi/transport v0.4.0/go.mod h1:uoCleTaQiFtoatEiiqcXFZ5OxIp6s1DfGeVsCVbalT4= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= @@ -35,10 +46,18 @@ github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5 github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= @@ -46,15 +65,17 @@ github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/go.work.sum b/go.work.sum index e084b7b..4c8099d 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,15 +1,25 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/webrpc/gen-typescript v0.16.1/go.mod h1:xQzYnVaSMfcygDXA5SuW8eYyCLHBHkj15wCF7gcJF5Y= github.com/webrpc/webrpc v0.22.0/go.mod h1:eeABnLz9BC4F9GGw6UKebVPkzkFYLrZRlcOvh6o8n10= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= diff --git a/middleware.go b/middleware.go index 8acc846..d3a2700 100644 --- a/middleware.go +++ b/middleware.go @@ -1,13 +1,17 @@ package authcontrol import ( + "cmp" "context" "errors" "log/slog" "net/http" + "strconv" "strings" "time" + "github.com/go-chi/chi/v5/middleware" + "github.com/go-chi/httplog/v3" "github.com/go-chi/jwtauth/v5" "github.com/lestrrat-go/jwx/v2/jwt" @@ -138,13 +142,17 @@ func Session(cfg Options) func(next http.Handler) http.Handler { ctx := r.Context() // if a custom middleware already sets the session type, skip this middleware - if _, ok := GetSessionType(ctx); ok { + if sessionType, ok := GetSessionType(ctx); ok { + httplog.SetAttrs(ctx, slog.String("sessionType", sessionType.String())) next.ServeHTTP(w, r) return } - sessionType := proto.SessionType_Public - var accessKey string + var ( + sessionType = proto.SessionType_Public + accessKey string + projectID uint64 + ) for _, f := range cfg.AccessKeyFuncs { if accessKey = f(r); accessKey != "" { @@ -171,7 +179,7 @@ func Session(cfg Options) func(next http.Handler) http.Handler { switch { case serviceClaim != "": ctx = WithService(ctx, serviceClaim) - sessionType = proto.SessionType_InternalService + sessionType = proto.SessionType_S2S case accountClaim != "": ctx = WithAccount(ctx, accountClaim) @@ -199,13 +207,18 @@ func Session(cfg Options) func(next http.Handler) http.Handler { } if projectClaim > 0 { - ctx = WithProjectID(ctx, uint64(projectClaim)) + projectID = uint64(projectClaim) sessionType = max(sessionType, proto.SessionType_Project) } else if projectIDClaim > 0 { - ctx = WithProjectID(ctx, uint64(projectIDClaim)) + projectID = uint64(projectIDClaim) sessionType = max(sessionType, proto.SessionType_Project) } + if projectID > 0 { + ctx = WithProjectID(ctx, projectID) + httplog.SetAttrs(ctx, slog.Uint64("projectId", projectID)) + } + // Restrict CORS for Builder Admin API Secret Keys. // These keys are designed for backend service use by third-party customers, not for web apps. if accountClaim != "" && projectClaim > 0 { @@ -215,12 +228,12 @@ func Session(cfg Options) func(next http.Handler) http.Handler { origin := r.Header.Get("Origin") if origin != "" { - err := proto.ErrSecretKeyCorsDisallowed.WithCausef("project_id: %v", projectClaim) + err := proto.ErrSecretKeyCorsDisallowed.WithCausef("project_id: %v", projectID) slog.ErrorContext(ctx, "CORS disallowed for Secret Key", slog.Any("error", err), slog.String("origin", origin), - slog.Uint64("project_id", uint64(projectClaim)), + slog.Uint64("project_id", projectID), ) // TODO: Uncomment once we're confident it won't disrupt major customers. @@ -236,7 +249,30 @@ func Session(cfg Options) func(next http.Handler) http.Handler { } ctx = WithSessionType(ctx, sessionType) - next.ServeHTTP(w, r.WithContext(ctx)) + httplog.SetAttrs(ctx, slog.String("sessionType", sessionType.String())) + + ww, ok := w.(middleware.WrapResponseWriter) + if !ok { + ww = middleware.NewWrapResponseWriter(w, r.ProtoMajor) + } + + defer func() { + // Track requests by session type. + sessionTypeCounter.Inc(sessionLabels{ + SessionType: sessionType.String(), + Status: strconv.Itoa(cmp.Or(ww.Status(), 200)), + }) + + // Track requests by project ID. + if projectID > 0 { + projectCounter.Inc(projectLabels{ + ProjectID: strconv.FormatUint(projectID, 10), + Status: strconv.Itoa(cmp.Or(ww.Status(), 200)), + }) + } + }() + + next.ServeHTTP(ww, r.WithContext(ctx)) }) } } diff --git a/proto/authcontrol.gen.go b/proto/authcontrol.gen.go index 7e50cd6..6ecbcd5 100644 --- a/proto/authcontrol.gen.go +++ b/proto/authcontrol.gen.go @@ -1,4 +1,4 @@ -// authcontrol v0.9.1 6d8f688a98165b12e0ddfa4ecbaeb8bd7d7f92ac +// authcontrol v0.9.1 efc70751a8d3d04b62886c568ebe71265a4e3d5b // -- // Code generated by webrpc-gen@v0.22.1 with golang generator. DO NOT EDIT. // @@ -29,7 +29,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "6d8f688a98165b12e0ddfa4ecbaeb8bd7d7f92ac" + return "efc70751a8d3d04b62886c568ebe71265a4e3d5b" } type WebrpcGenVersions struct { @@ -103,7 +103,7 @@ const ( // Admin-level access (jwt) SessionType_Admin SessionType = 5 // Internal service-to-service access (jwt) - SessionType_InternalService SessionType = 6 + SessionType_S2S SessionType = 6 ) var SessionType_name = map[uint16]string{ @@ -113,17 +113,17 @@ var SessionType_name = map[uint16]string{ 3: "Project", 4: "User", 5: "Admin", - 6: "InternalService", + 6: "S2S", } var SessionType_value = map[string]uint16{ - "Public": 0, - "Wallet": 1, - "AccessKey": 2, - "Project": 3, - "User": 4, - "Admin": 5, - "InternalService": 6, + "Public": 0, + "Wallet": 1, + "AccessKey": 2, + "Project": 3, + "User": 4, + "Admin": 5, + "S2S": 6, } func (x SessionType) String() string { diff --git a/proto/authcontrol.gen.ts b/proto/authcontrol.gen.ts index 62250e0..8d26e76 100644 --- a/proto/authcontrol.gen.ts +++ b/proto/authcontrol.gen.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -// authcontrol v0.9.1 6d8f688a98165b12e0ddfa4ecbaeb8bd7d7f92ac +// authcontrol v0.9.1 efc70751a8d3d04b62886c568ebe71265a4e3d5b // -- // Code generated by webrpc-gen@v0.22.1 with typescript generator. DO NOT EDIT. // @@ -16,7 +16,7 @@ export const WebRPCVersion = "v1" export const WebRPCSchemaVersion = "v0.9.1" // Schema hash generated from your RIDL schema -export const WebRPCSchemaHash = "6d8f688a98165b12e0ddfa4ecbaeb8bd7d7f92ac" +export const WebRPCSchemaHash = "efc70751a8d3d04b62886c568ebe71265a4e3d5b" type WebrpcGenVersions = { webrpcGenVersion: string; @@ -78,7 +78,7 @@ export enum SessionType { Project = 'Project', User = 'User', Admin = 'Admin', - InternalService = 'InternalService' + S2S = 'S2S' } diff --git a/proto/authcontrol.ridl b/proto/authcontrol.ridl index 2329502..67051d5 100644 --- a/proto/authcontrol.ridl +++ b/proto/authcontrol.ridl @@ -4,12 +4,13 @@ name = authcontrol version = v0.9.1 enum SessionType: uint16 - - Public # Public access (anonymous) - - Wallet # Wallet access (wallet signed proof to jwt) - - AccessKey # API access via a project *public* X-Access-Key (no jwt) - - Project # Project access via *private* jwt scoped for the project (jwt) - - User # User-level access (jwt) - - Admin # Admin-level access (jwt) - - InternalService # Internal service-to-service access (jwt) - -import "./authcontrol.errors.ridl" \ No newline at end of file + - Public # Public access (anonymous) + - Wallet # Wallet access (wallet signed proof to jwt) + - AccessKey # API access via a project *public* X-Access-Key (no jwt) + - Project # Project access via *private* jwt scoped for the project (jwt) + - User # User-level access (jwt) + - Admin # Admin-level access (jwt) + - S2S # Internal service-to-service access (jwt) + +import "./authcontrol.errors.ridl" + diff --git a/proto/proto.go b/proto/proto.go index abea749..40371af 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -2,13 +2,17 @@ //go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authcontrol.ridl -target=typescript -client -out=./authcontrol.gen.ts package proto -const SessionType_Max SessionType = SessionType_InternalService + 1 +const SessionType_Max SessionType = SessionType_S2S + 1 // AndUp returns a list of all session types from the current one up to the maximum. func (s SessionType) OrHigher() []SessionType { - list := make([]SessionType, 0, SessionType_InternalService-s+1) + list := make([]SessionType, 0, SessionType_S2S-s+1) for i := s; i < SessionType_Max; i++ { list = append(list, i) } return list } + +// Deprecated: Use SessionType_S2S instead. +// Note: Remove this after some time. +const SessionType_InternalService = SessionType_S2S diff --git a/telemetry.go b/telemetry.go new file mode 100644 index 0000000..8ad7be4 --- /dev/null +++ b/telemetry.go @@ -0,0 +1,20 @@ +package authcontrol + +import ( + "github.com/go-chi/metrics" +) + +var ( + sessionTypeCounter = metrics.CounterWith[sessionLabels]("authcontrol_requests_total", "Total number of requests by session type.") + projectCounter = metrics.CounterWith[projectLabels]("authcontrol_project_requests_total", "Total number of requests by project ID.") +) + +type sessionLabels struct { + SessionType string `label:"session_type"` + Status string `label:"status"` +} + +type projectLabels struct { + ProjectID string `label:"project_id"` + Status string `label:"status"` +}