Skip to content

Commit 4f8d1d5

Browse files
authored
feat: add Prometheus metrics, health checks, and readiness endpoints (#528)
* feat: add prometheus metrics, health checks, and readiness endpoints - Add github.com/prometheus/client_golang dependency - Create internal/metrics package registering HTTPRequestsTotal, HTTPRequestDuration, AuthEventsTotal, and ActiveSessions collectors - Add HealthCheck(ctx) method to the storage.Provider interface and implement it for all six DB providers (sql, mongodb, arangodb, cassandradb, dynamodb, couchbase) - Replace the simple /health string handler with a storage-backed JSON liveness handler (/healthz) and a new readiness handler (/readyz) - Add MetricsMiddleware() and MetricsHandler() to the http_handlers.Provider interface and implement them - Register /healthz, /readyz, /metrics routes and MetricsMiddleware in the Gin router - Call metrics.Init() during server startup in cmd/root.go - Add integration tests for /healthz and /readyz endpoints * feat: add security metrics, GraphQL error tracking, and auth event instrumentation - Add security metrics (authorizer_security_events_total) for failed logins, invalid credentials, revoked accounts, and failed admin auth - Add GraphQL error metrics (authorizer_graphql_errors_total) to capture errors in HTTP 200 responses using gqlgen AroundOperations middleware - Add GraphQL operation duration histogram (authorizer_graphql_request_duration_seconds) - Add DB health check counter (authorizer_db_health_check_total) - Instrument auth handlers: login, signup, logout, admin_login, admin_logout, forgot_password, reset_password with metrics.RecordAuthEvent calls - Track active sessions gauge on login/signup (inc) and logout (dec) - Add helper functions RecordAuthEvent, RecordSecurityEvent, RecordGraphQLError - Make metrics.Init() idempotent with sync.Once for safe test usage - Migrate health_test.go from legacy getTestConfig to runForEachDB pattern - Add comprehensive integration tests for all metrics (TestMetricsEndpoint, TestMetricsMiddleware, TestDBHealthCheckMetrics, TestAuthEventMetrics, TestGraphQLErrorMetrics, TestAdminLoginMetrics, TestForgotPasswordMetrics) * feat: add audit logs and metrics to OAuth/token HTTP handlers - oauth_login.go: Add AuditOAuthLoginInitiatedEvent audit log + metrics - oauth_callback.go: Add AuditOAuthCallbackFailedEvent for error paths (user info failure, revoked account) + success/failure metrics - token.go: Add security metric for invalid_client + token success metrics - revoke_refresh_token.go: Add EventTokenRevoke metric on success - logout.go: Add EventLogout metric + ActiveSessions decrement - verify_email.go: Add AuditEmailVerifiedEvent audit log + metrics
1 parent d08594d commit 4f8d1d5

32 files changed

Lines changed: 823 additions & 18 deletions

cmd/root.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/authorizerdev/authorizer/internal/events"
2020
"github.com/authorizerdev/authorizer/internal/http_handlers"
2121
"github.com/authorizerdev/authorizer/internal/memory_store"
22+
"github.com/authorizerdev/authorizer/internal/metrics"
2223
"github.com/authorizerdev/authorizer/internal/oauth"
2324
"github.com/authorizerdev/authorizer/internal/server"
2425
"github.com/authorizerdev/authorizer/internal/sms"
@@ -310,6 +311,9 @@ func runRoot(c *cobra.Command, args []string) {
310311
Level(zeroLogLevel).
311312
With().Timestamp().Logger()
312313

314+
// Initialize prometheus metrics
315+
metrics.Init()
316+
313317
// Derive IsEmailServiceEnabled from SMTP config
314318
rootArgs.config.IsEmailServiceEnabled = strings.TrimSpace(rootArgs.config.SMTPHost) != "" &&
315319
rootArgs.config.SMTPPort > 0 &&

go.mod

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ require (
1717
github.com/google/uuid v1.6.0
1818
github.com/guregu/dynamo v1.20.2
1919
github.com/pquerna/otp v1.4.0
20+
github.com/prometheus/client_golang v1.23.2
2021
github.com/redis/go-redis/v9 v9.6.3
2122
github.com/robertkrimen/otto v0.2.1
2223
github.com/rs/zerolog v1.33.0
2324
github.com/spf13/cobra v1.8.1
24-
github.com/stretchr/testify v1.10.0
25+
github.com/stretchr/testify v1.11.1
2526
github.com/twilio/twilio-go v1.14.1
2627
github.com/vektah/gqlparser/v2 v2.5.26
2728
go.mongodb.org/mongo-driver v1.12.1
@@ -39,6 +40,7 @@ require (
3940
github.com/agnivade/levenshtein v1.2.1 // indirect
4041
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
4142
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
43+
github.com/beorn7/perks v1.0.1 // indirect
4244
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
4345
github.com/bytedance/sonic v1.9.1 // indirect
4446
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
@@ -76,7 +78,7 @@ require (
7678
github.com/jinzhu/now v1.1.5 // indirect
7779
github.com/jmespath/go-jmespath v0.4.0 // indirect
7880
github.com/json-iterator/go v1.1.12 // indirect
79-
github.com/klauspost/compress v1.15.15 // indirect
81+
github.com/klauspost/compress v1.18.0 // indirect
8082
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
8183
github.com/leodido/go-urn v1.2.4 // indirect
8284
github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect
@@ -87,9 +89,13 @@ require (
8789
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8890
github.com/modern-go/reflect2 v1.0.2 // indirect
8991
github.com/montanaflynn/stats v0.7.0 // indirect
92+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
9093
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
9194
github.com/pkg/errors v0.9.1 // indirect
9295
github.com/pmezard/go-difflib v1.0.0 // indirect
96+
github.com/prometheus/client_model v0.6.2 // indirect
97+
github.com/prometheus/common v0.66.1 // indirect
98+
github.com/prometheus/procfs v0.16.1 // indirect
9399
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
94100
github.com/rogpeppe/go-internal v1.11.0 // indirect
95101
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -103,14 +109,15 @@ require (
103109
github.com/xdg-go/stringprep v1.0.4 // indirect
104110
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
105111
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
112+
go.yaml.in/yaml/v2 v2.4.2 // indirect
106113
golang.org/x/arch v0.3.0 // indirect
107114
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
108115
golang.org/x/mod v0.30.0 // indirect
109116
golang.org/x/net v0.47.0 // indirect
110117
golang.org/x/sys v0.39.0 // indirect
111118
golang.org/x/text v0.32.0 // indirect
112119
golang.org/x/tools v0.39.0 // indirect
113-
google.golang.org/protobuf v1.36.6 // indirect
120+
google.golang.org/protobuf v1.36.8 // indirect
114121
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
115122
gopkg.in/inf.v0 v0.9.1 // indirect
116123
gopkg.in/sourcemap.v1 v1.0.5 // indirect

go.sum

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ github.com/aws/aws-sdk-go v1.44.306/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8
3838
github.com/aws/aws-sdk-go v1.47.4 h1:IyhNbmPt+5ldi5HNzv7ZnXiqSglDMaJiZlzj4Yq3qnk=
3939
github.com/aws/aws-sdk-go v1.47.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
4040
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
41+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
42+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
4143
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
4244
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
4345
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
@@ -154,8 +156,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
154156
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
155157
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
156158
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
157-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
158-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
159+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
160+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
159161
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
160162
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
161163
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
@@ -205,14 +207,14 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
205207
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
206208
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
207209
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
208-
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
209-
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
210+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
211+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
210212
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
211213
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
212214
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
213215
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
214-
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
215-
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
216+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
217+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
216218
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
217219
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
218220
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -250,6 +252,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P
250252
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
251253
github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU=
252254
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
255+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
256+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
253257
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
254258
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
255259
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
@@ -261,6 +265,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
261265
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
262266
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
263267
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
268+
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
269+
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
270+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
271+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
272+
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
273+
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
274+
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
275+
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
264276
github.com/redis/go-redis/v9 v9.6.3 h1:8Dr5ygF1QFXRxIH/m3Xg9MMG1rS8YCtAgosrsewT6i0=
265277
github.com/redis/go-redis/v9 v9.6.3/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
266278
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -298,8 +310,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
298310
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
299311
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
300312
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
301-
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
302-
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
313+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
314+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
303315
github.com/twilio/twilio-go v1.14.1 h1:uyMwNe2naFKwxLpVflAHbKEPiW9iHNI8VF6NWLJJ1Kk=
304316
github.com/twilio/twilio-go v1.14.1/go.mod h1:tdnfQ5TjbewoAu4lf9bMsGvfuJ/QU9gYuv9yx3TSIXU=
305317
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
@@ -326,6 +338,10 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
326338
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
327339
go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE=
328340
go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
341+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
342+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
343+
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
344+
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
329345
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
330346
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
331347
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -432,8 +448,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
432448
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
433449
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
434450
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
435-
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
436-
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
451+
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
452+
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
437453
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
438454
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
439455
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/graphql/admin_login.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/authorizerdev/authorizer/internal/cookie"
1010
"github.com/authorizerdev/authorizer/internal/crypto"
1111
"github.com/authorizerdev/authorizer/internal/graph/model"
12+
"github.com/authorizerdev/authorizer/internal/metrics"
1213
"github.com/authorizerdev/authorizer/internal/utils"
1314
)
1415

@@ -24,6 +25,8 @@ func (g *graphqlProvider) AdminLogin(ctx context.Context, params *model.AdminLog
2425
}
2526
if params.AdminSecret != g.Config.AdminSecret {
2627
log.Debug().Msg("Invalid admin secret")
28+
metrics.RecordAuthEvent(metrics.EventAdminLogin, metrics.StatusFailure)
29+
metrics.RecordSecurityEvent("invalid_admin_secret", "admin_login")
2730
g.AuditProvider.LogEvent(audit.Event{
2831
Action: constants.AuditAdminLoginFailedEvent,
2932
ActorType: constants.AuditActorTypeAdmin,
@@ -40,6 +43,7 @@ func (g *graphqlProvider) AdminLogin(ctx context.Context, params *model.AdminLog
4043
}
4144
cookie.SetAdminCookie(gc, hashedKey, g.Config.AdminCookieSecure)
4245

46+
metrics.RecordAuthEvent(metrics.EventAdminLogin, metrics.StatusSuccess)
4347
g.AuditProvider.LogEvent(audit.Event{
4448
Action: constants.AuditAdminLoginSuccessEvent,
4549
ActorType: constants.AuditActorTypeAdmin,

internal/graphql/admin_logout.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/authorizerdev/authorizer/internal/constants"
99
"github.com/authorizerdev/authorizer/internal/cookie"
1010
"github.com/authorizerdev/authorizer/internal/graph/model"
11+
"github.com/authorizerdev/authorizer/internal/metrics"
1112
"github.com/authorizerdev/authorizer/internal/utils"
1213
)
1314

@@ -26,6 +27,7 @@ func (g *graphqlProvider) AdminLogout(ctx context.Context) (*model.Response, err
2627
}
2728

2829
cookie.DeleteAdminCookie(gc, g.Config.AdminCookieSecure)
30+
metrics.RecordAuthEvent(metrics.EventAdminLogout, metrics.StatusSuccess)
2931
g.AuditProvider.LogEvent(audit.Event{
3032
Action: constants.AuditAdminLogoutEvent,
3133
ActorType: constants.AuditActorTypeAdmin,

internal/graphql/forgot_password.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/authorizerdev/authorizer/internal/constants"
1313
"github.com/authorizerdev/authorizer/internal/cookie"
1414
"github.com/authorizerdev/authorizer/internal/graph/model"
15+
"github.com/authorizerdev/authorizer/internal/metrics"
1516
"github.com/authorizerdev/authorizer/internal/parsers"
1617
"github.com/authorizerdev/authorizer/internal/refs"
1718
"github.com/authorizerdev/authorizer/internal/storage/schemas"
@@ -60,6 +61,7 @@ func (g *graphqlProvider) ForgotPassword(ctx context.Context, params *model.Forg
6061
log.Debug().Err(err).Msg("Failed to get user by phone number")
6162
}
6263
if err != nil {
64+
metrics.RecordAuthEvent(metrics.EventForgotPwd, metrics.StatusFailure)
6365
return nil, fmt.Errorf(`bad user credentials`)
6466
}
6567
hostname := parsers.GetHost(gc)
@@ -127,6 +129,7 @@ func (g *graphqlProvider) ForgotPassword(ctx context.Context, params *model.Forg
127129
IPAddress: utils.GetIP(gc.Request),
128130
UserAgent: utils.GetUserAgent(gc.Request),
129131
})
132+
metrics.RecordAuthEvent(metrics.EventForgotPwd, metrics.StatusSuccess)
130133
return &model.ForgotPasswordResponse{
131134
Message: `Please check your inbox! We have sent a password reset link.`,
132135
}, nil
@@ -168,6 +171,7 @@ func (g *graphqlProvider) ForgotPassword(ctx context.Context, params *model.Forg
168171
IPAddress: utils.GetIP(gc.Request),
169172
UserAgent: utils.GetUserAgent(gc.Request),
170173
})
174+
metrics.RecordAuthEvent(metrics.EventForgotPwd, metrics.StatusSuccess)
171175
return &model.ForgotPasswordResponse{
172176
Message: "Please enter the OTP sent to your phone number and change your password.",
173177
ShouldShowMobileOtpScreen: refs.NewBoolRef(true),

internal/graphql/login.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/authorizerdev/authorizer/internal/constants"
1414
"github.com/authorizerdev/authorizer/internal/cookie"
1515
"github.com/authorizerdev/authorizer/internal/graph/model"
16+
"github.com/authorizerdev/authorizer/internal/metrics"
1617
"github.com/authorizerdev/authorizer/internal/parsers"
1718
"github.com/authorizerdev/authorizer/internal/refs"
1819
"github.com/authorizerdev/authorizer/internal/storage/schemas"
@@ -61,10 +62,14 @@ func (g *graphqlProvider) Login(ctx context.Context, params *model.LoginRequest)
6162
log.Debug().Str("phone_number", phoneNumber).Msg("User found by phone number")
6263
}
6364
if err != nil {
65+
metrics.RecordAuthEvent(metrics.EventLogin, metrics.StatusFailure)
66+
metrics.RecordSecurityEvent("invalid_credentials", "user_not_found")
6467
return nil, fmt.Errorf(`user not found`)
6568
}
6669
if user.RevokedTimestamp != nil {
6770
log.Debug().Msg("User access has been revoked")
71+
metrics.RecordAuthEvent(metrics.EventLogin, metrics.StatusFailure)
72+
metrics.RecordSecurityEvent("account_revoked", "login_attempt")
6873
return nil, fmt.Errorf(`user access has been revoked`)
6974
}
7075
isEmailServiceEnabled := g.Config.IsEmailServiceEnabled
@@ -189,6 +194,8 @@ func (g *graphqlProvider) Login(ctx context.Context, params *model.LoginRequest)
189194
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
190195
if err != nil {
191196
log.Debug().Msg("Bad user credentials")
197+
metrics.RecordAuthEvent(metrics.EventLogin, metrics.StatusFailure)
198+
metrics.RecordSecurityEvent("invalid_credentials", "bad_password")
192199
g.AuditProvider.LogEvent(audit.Event{
193200
Action: constants.AuditLoginFailedEvent,
194201
ActorID: user.ID,
@@ -396,6 +403,8 @@ func (g *graphqlProvider) Login(ctx context.Context, params *model.LoginRequest)
396403
IP: utils.GetIP(gc.Request),
397404
})
398405
}()
406+
metrics.RecordAuthEvent(metrics.EventLogin, metrics.StatusSuccess)
407+
metrics.ActiveSessions.Inc()
399408
g.AuditProvider.LogEvent(audit.Event{
400409
Action: constants.AuditLoginSuccessEvent,
401410
ActorID: user.ID,

internal/graphql/logout.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/authorizerdev/authorizer/internal/constants"
88
"github.com/authorizerdev/authorizer/internal/cookie"
99
"github.com/authorizerdev/authorizer/internal/graph/model"
10+
"github.com/authorizerdev/authorizer/internal/metrics"
1011
"github.com/authorizerdev/authorizer/internal/utils"
1112
)
1213

@@ -36,6 +37,8 @@ func (g *graphqlProvider) Logout(ctx context.Context) (*model.Response, error) {
3637
return nil, err
3738
}
3839
cookie.DeleteSession(gc, g.Config.AppCookieSecure)
40+
metrics.RecordAuthEvent(metrics.EventLogout, metrics.StatusSuccess)
41+
metrics.ActiveSessions.Dec()
3942
g.AuditProvider.LogEvent(audit.Event{
4043
Action: constants.AuditLogoutEvent,
4144
ActorID: tokenData.UserID,

internal/graphql/reset_password.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/authorizerdev/authorizer/internal/cookie"
1212
"github.com/authorizerdev/authorizer/internal/crypto"
1313
"github.com/authorizerdev/authorizer/internal/graph/model"
14+
"github.com/authorizerdev/authorizer/internal/metrics"
1415
"github.com/authorizerdev/authorizer/internal/parsers"
1516
"github.com/authorizerdev/authorizer/internal/refs"
1617
"github.com/authorizerdev/authorizer/internal/storage/schemas"
@@ -182,6 +183,7 @@ func (g *graphqlProvider) ResetPassword(ctx context.Context, params *model.Reset
182183
IPAddress: utils.GetIP(gc.Request),
183184
UserAgent: utils.GetUserAgent(gc.Request),
184185
})
186+
metrics.RecordAuthEvent(metrics.EventResetPwd, metrics.StatusSuccess)
185187
return &model.Response{
186188
Message: `Password updated successfully.`,
187189
}, nil

0 commit comments

Comments
 (0)