From cb8b400dca5207dab65978c8daa187c569423c57 Mon Sep 17 00:00:00 2001 From: Eric Zorn Date: Mon, 6 Jan 2025 18:30:39 -0500 Subject: [PATCH 1/2] FEAT: Backend Auth Completed for HTTP (#36) * feat: adding auth package empty * feat: adding auth * fix: use constants * fix: access token being sent for all resolvers * fix: abstract request * fix: scale the accounts api and apollo router to 2 machines * feat: adding auth middleware to the GraphQL template * fix: validation for accounts resolver * fix: accounts graphql resolver to fetch account * fix: further validation * fix: further email validation * feat: change auth package to http-auth * feat: updating the auth package name to httpauth * feat: adding support for httpauth package * feat: adding telemetry to apollo router in dev and prod * feat: adding environment variables to apollo router * fix: docker compose --- apps/services/accounts-api/cmd/server/main.go | 4 +-- .../accounts-graphql/cmd/server/main.go | 5 ++-- .../graph/resolvers/accounts.resolvers.go | 27 +++++++++---------- .../graph/resolvers/schema.resolvers.go | 6 ++--- apps/services/apollo-router/.env.example | 2 ++ .../apollo-router/supergraph-prod.yaml | 6 +++++ docker-compose.yml | 2 ++ go.work | 2 +- graphql/supergraph-dev.yaml | 6 +++++ libs/backend/auth/go.mod | 11 -------- libs/backend/{auth => httpauth}/auth.go | 2 +- libs/backend/{auth => httpauth}/constants.go | 2 +- libs/backend/{auth => httpauth}/context.go | 2 +- libs/backend/{auth => httpauth}/errors.go | 2 +- libs/backend/httpauth/go.mod | 15 +++++++++++ libs/backend/{auth => httpauth}/go.sum | 8 ++++++ .../{auth => httpauth}/interceptors.go | 2 +- libs/backend/{auth => httpauth}/jwt.go | 2 +- libs/backend/{auth => httpauth}/middleware.go | 2 +- libs/backend/{auth => httpauth}/project.json | 4 +-- .../graphql-files/cmd/server/main.go.template | 3 ++- 21 files changed, 71 insertions(+), 44 deletions(-) create mode 100644 apps/services/apollo-router/.env.example delete mode 100644 libs/backend/auth/go.mod rename libs/backend/{auth => httpauth}/auth.go (91%) rename libs/backend/{auth => httpauth}/constants.go (87%) rename libs/backend/{auth => httpauth}/context.go (98%) rename libs/backend/{auth => httpauth}/errors.go (92%) create mode 100644 libs/backend/httpauth/go.mod rename libs/backend/{auth => httpauth}/go.sum (70%) rename libs/backend/{auth => httpauth}/interceptors.go (99%) rename libs/backend/{auth => httpauth}/jwt.go (99%) rename libs/backend/{auth => httpauth}/middleware.go (96%) rename libs/backend/{auth => httpauth}/project.json (84%) diff --git a/apps/services/accounts-api/cmd/server/main.go b/apps/services/accounts-api/cmd/server/main.go index dbdf512..9fee895 100644 --- a/apps/services/accounts-api/cmd/server/main.go +++ b/apps/services/accounts-api/cmd/server/main.go @@ -19,8 +19,8 @@ import ( connectrpcadapter "apps/services/accounts-api/internal/adapters/connectrpc" "apps/services/accounts-api/internal/adapters/database/repositories" - "libs/backend/auth" "libs/backend/boot" + "libs/backend/httpauth" "libs/backend/proto-gen/go/accounts/accountsapi/v1/accountsapiv1connect" ) @@ -49,7 +49,7 @@ func run() error { } // Custom interceptors - authInterceptor := auth.NewAuthInterceptor(logger) + authInterceptor := httpauth.NewAuthInterceptor(logger) options := []connect.HandlerOption{ connect.WithInterceptors( diff --git a/apps/services/accounts-graphql/cmd/server/main.go b/apps/services/accounts-graphql/cmd/server/main.go index bf518f2..8671b8e 100644 --- a/apps/services/accounts-graphql/cmd/server/main.go +++ b/apps/services/accounts-graphql/cmd/server/main.go @@ -6,8 +6,9 @@ import ( "apps/services/accounts-graphql/internal/graph/resolvers" "context" "errors" - "libs/backend/auth" + "libs/backend/boot" "libs/backend/cache" + auth "libs/backend/httpauth" "log" "log/slog" "os" @@ -21,8 +22,6 @@ import ( "github.com/vektah/gqlparser/v2/ast" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" - - "libs/backend/boot" ) // serviceName is the name of the microservice diff --git a/apps/services/accounts-graphql/internal/graph/resolvers/accounts.resolvers.go b/apps/services/accounts-graphql/internal/graph/resolvers/accounts.resolvers.go index 7304289..e56cb03 100644 --- a/apps/services/accounts-graphql/internal/graph/resolvers/accounts.resolvers.go +++ b/apps/services/accounts-graphql/internal/graph/resolvers/accounts.resolvers.go @@ -8,7 +8,7 @@ import ( "apps/services/accounts-graphql/internal/graph/models" "context" "fmt" - "libs/backend/auth" + "libs/backend/httpauth" accountsapiv1 "libs/backend/proto-gen/go/accounts/accountsapi/v1" "log/slog" "time" @@ -24,12 +24,12 @@ func (r *mutationResolver) DeleteAccount(ctx context.Context, commonID uuid.UUID // Call Accounts API const hardDelete = false - accessToken := auth.GetAuthTokenFromContext(ctx) + accessToken := httpauth.GetAuthTokenFromContext(ctx) req := connect.NewRequest(&accountsapiv1.DeleteAccountRequest{ CommonId: commonID.String(), HardDelete: hardDelete, }) - req.Header().Add(auth.AuthorizationHeaderKey, accessToken) + req.Header().Add(httpauth.AuthorizationHeaderKey, accessToken) resp, err := r.AccountsAPIClient.DeleteAccount(ctx, req) @@ -49,28 +49,27 @@ func (r *queryResolver) Account(ctx context.Context, input models.RetrieveAccoun commonID := input.CommonID emailAddress := input.EmailAddress - var commonIDForSearch *string - var emailAddressForSearch *string - + // Construct proper request + var req *connect.Request[accountsapiv1.GetAccountRequest] switch { case commonID != nil: commonIDStr := commonID.String() - commonIDForSearch = &commonIDStr + req = connect.NewRequest(&accountsapiv1.GetAccountRequest{ + CommonId: &commonIDStr, + }) loggerValues = append(loggerValues, slog.String("commonID", commonIDStr)) case emailAddress != nil: - emailAddressForSearch = emailAddress loggerValues = append(loggerValues, slog.String("emailAddress", *emailAddress)) + req = connect.NewRequest(&accountsapiv1.GetAccountRequest{ + EmailAddress: emailAddress, + }) } r.Logger.Info("Fetching account", loggerValues...) // Call the accounts API - req := connect.NewRequest(&accountsapiv1.GetAccountRequest{ - CommonId: commonIDForSearch, - EmailAddress: emailAddressForSearch, - }) - authHeader := auth.GetAuthTokenFromContext(ctx) - req.Header().Add(auth.AuthorizationHeaderKey, authHeader) + authHeader := httpauth.GetAuthTokenFromContext(ctx) + req.Header().Add(httpauth.AuthorizationHeaderKey, authHeader) resp, err := r.AccountsAPIClient.GetAccount(ctx, req) // Check if there was an error or if the account is nil diff --git a/apps/services/accounts-graphql/internal/graph/resolvers/schema.resolvers.go b/apps/services/accounts-graphql/internal/graph/resolvers/schema.resolvers.go index 85b0ad1..a906e67 100644 --- a/apps/services/accounts-graphql/internal/graph/resolvers/schema.resolvers.go +++ b/apps/services/accounts-graphql/internal/graph/resolvers/schema.resolvers.go @@ -9,7 +9,7 @@ import ( "apps/services/accounts-graphql/internal/graph/models" "context" "fmt" - "libs/backend/auth" + "libs/backend/httpauth" accountsapiv1 "libs/backend/proto-gen/go/accounts/accountsapi/v1" "connectrpc.com/connect" @@ -34,8 +34,8 @@ func (r *queryResolver) Viewer(ctx context.Context, commonID uuid.UUID) (*models req := connect.NewRequest(&accountsapiv1.GetAccountRequest{ CommonId: &commonIDStr, }) - authHeader := auth.GetAuthTokenFromContext(ctx) - req.Header().Add(auth.AuthorizationHeaderKey, authHeader) + authHeader := httpauth.GetAuthTokenFromContext(ctx) + req.Header().Add(httpauth.AuthorizationHeaderKey, authHeader) resp, err := r.AccountsAPIClient.GetAccount(ctx, req) // Check if there was an error or if the account is nil diff --git a/apps/services/apollo-router/.env.example b/apps/services/apollo-router/.env.example new file mode 100644 index 0000000..a53236a --- /dev/null +++ b/apps/services/apollo-router/.env.example @@ -0,0 +1,2 @@ +APOLLO_KEY="" +APOLLO_REF="" diff --git a/apps/services/apollo-router/supergraph-prod.yaml b/apps/services/apollo-router/supergraph-prod.yaml index 88ca21f..9176365 100644 --- a/apps/services/apollo-router/supergraph-prod.yaml +++ b/apps/services/apollo-router/supergraph-prod.yaml @@ -5,3 +5,9 @@ subgraphs: routing_url: http://accounts-graphql-prod.internal:8080/graphql # <- can be omitted if the same as introspection URL schema: subgraph_url: http://localhost:3003/graphql +include_subgraph_errors: + all: true +telemetry: + instrumentation: + spans: + mode: spec_compliant diff --git a/docker-compose.yml b/docker-compose.yml index 1527c75..59b73b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -102,6 +102,8 @@ services: container_name: apollo-router ports: - '4000:4000' + env_file: + - ./apps/services/apollo-router/.env.local volumes: - ./graphql/supergraph-dev.yaml:/supergraph.yaml - ./graphql/supergraph-dev.graphql:/supergraph.graphql diff --git a/go.work b/go.work index e651388..093da78 100644 --- a/go.work +++ b/go.work @@ -5,7 +5,7 @@ use ( ./apps/services/accounts-graphql ./apps/services/accounts-worker ./apps/services/inbound-webhooks-api - ./libs/backend/auth + ./libs/backend/httpauth ./libs/backend/boot ./libs/backend/cache ./libs/backend/domain/user diff --git a/graphql/supergraph-dev.yaml b/graphql/supergraph-dev.yaml index 2c098fb..55ac7d5 100644 --- a/graphql/supergraph-dev.yaml +++ b/graphql/supergraph-dev.yaml @@ -5,3 +5,9 @@ subgraphs: routing_url: http://accounts-graphql:3000/graphql # <- can be omitted if the same as introspection URL schema: subgraph_url: http://localhost:3003/graphql +include_subgraph_errors: + all: true +telemetry: + instrumentation: + spans: + mode: spec_compliant diff --git a/libs/backend/auth/go.mod b/libs/backend/auth/go.mod deleted file mode 100644 index 604bac0..0000000 --- a/libs/backend/auth/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module libs/backend/auth - -go 1.23 - -require github.com/auth0/go-jwt-middleware/v2 v2.2.2 - -require ( - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/sync v0.8.0 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect -) diff --git a/libs/backend/auth/auth.go b/libs/backend/httpauth/auth.go similarity index 91% rename from libs/backend/auth/auth.go rename to libs/backend/httpauth/auth.go index 7060199..536cd1d 100644 --- a/libs/backend/auth/auth.go +++ b/libs/backend/httpauth/auth.go @@ -1,4 +1,4 @@ -package auth +package httpauth import "context" diff --git a/libs/backend/auth/constants.go b/libs/backend/httpauth/constants.go similarity index 87% rename from libs/backend/auth/constants.go rename to libs/backend/httpauth/constants.go index 95b0ac5..d5a868b 100644 --- a/libs/backend/auth/constants.go +++ b/libs/backend/httpauth/constants.go @@ -1,4 +1,4 @@ -package auth +package httpauth const ( // Used for headers to be sent and recieved via HTTP and ConnectRPC diff --git a/libs/backend/auth/context.go b/libs/backend/httpauth/context.go similarity index 98% rename from libs/backend/auth/context.go rename to libs/backend/httpauth/context.go index cc715e0..f946547 100644 --- a/libs/backend/auth/context.go +++ b/libs/backend/httpauth/context.go @@ -1,4 +1,4 @@ -package auth +package httpauth import ( "context" diff --git a/libs/backend/auth/errors.go b/libs/backend/httpauth/errors.go similarity index 92% rename from libs/backend/auth/errors.go rename to libs/backend/httpauth/errors.go index 45aeee0..4ca277d 100644 --- a/libs/backend/auth/errors.go +++ b/libs/backend/httpauth/errors.go @@ -1,4 +1,4 @@ -package auth +package httpauth import "errors" diff --git a/libs/backend/httpauth/go.mod b/libs/backend/httpauth/go.mod new file mode 100644 index 0000000..18d1e4c --- /dev/null +++ b/libs/backend/httpauth/go.mod @@ -0,0 +1,15 @@ +module libs/backend/httpauth + +go 1.23 + +require ( + connectrpc.com/connect v1.17.0 + github.com/auth0/go-jwt-middleware/v2 v2.2.2 +) + +require ( + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/sync v0.8.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect +) diff --git a/libs/backend/auth/go.sum b/libs/backend/httpauth/go.sum similarity index 70% rename from libs/backend/auth/go.sum rename to libs/backend/httpauth/go.sum index 5a67e75..2bb0a1e 100644 --- a/libs/backend/auth/go.sum +++ b/libs/backend/httpauth/go.sum @@ -1,3 +1,5 @@ +connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk= +connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= github.com/auth0/go-jwt-middleware/v2 v2.2.2 h1:vrvkFZf72r3Qbt45KLjBG3/6Xq2r3NTixWKu2e8de9I= github.com/auth0/go-jwt-middleware/v2 v2.2.2/go.mod h1:4vwxpVtu/Kl4c4HskT+gFLjq0dra8F1joxzamrje6J0= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -10,8 +12,14 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/libs/backend/auth/interceptors.go b/libs/backend/httpauth/interceptors.go similarity index 99% rename from libs/backend/auth/interceptors.go rename to libs/backend/httpauth/interceptors.go index 812ce98..d4bfe6b 100644 --- a/libs/backend/auth/interceptors.go +++ b/libs/backend/httpauth/interceptors.go @@ -1,4 +1,4 @@ -package auth +package httpauth import ( "context" diff --git a/libs/backend/auth/jwt.go b/libs/backend/httpauth/jwt.go similarity index 99% rename from libs/backend/auth/jwt.go rename to libs/backend/httpauth/jwt.go index d2b6006..15a93ba 100644 --- a/libs/backend/auth/jwt.go +++ b/libs/backend/httpauth/jwt.go @@ -1,4 +1,4 @@ -package auth +package httpauth import ( "context" diff --git a/libs/backend/auth/middleware.go b/libs/backend/httpauth/middleware.go similarity index 96% rename from libs/backend/auth/middleware.go rename to libs/backend/httpauth/middleware.go index 28b2a4a..eb87b77 100644 --- a/libs/backend/auth/middleware.go +++ b/libs/backend/httpauth/middleware.go @@ -1,4 +1,4 @@ -package auth +package httpauth import ( "context" diff --git a/libs/backend/auth/project.json b/libs/backend/httpauth/project.json similarity index 84% rename from libs/backend/auth/project.json rename to libs/backend/httpauth/project.json index 6f3768c..9dcbc3e 100644 --- a/libs/backend/auth/project.json +++ b/libs/backend/httpauth/project.json @@ -1,8 +1,8 @@ { - "name": "auth", + "name": "httpauth", "$schema": "../../../node_modules/nx/schemas/project-schema.json", "projectType": "library", - "sourceRoot": "libs/backend/auth", + "sourceRoot": "libs/backend/httpauth", "tags": ["services", "api", "authentication"], "targets": { "test": { diff --git a/tools/backend-service/src/generators/service-gen/graphql-files/cmd/server/main.go.template b/tools/backend-service/src/generators/service-gen/graphql-files/cmd/server/main.go.template index 834700f..60aaaeb 100644 --- a/tools/backend-service/src/generators/service-gen/graphql-files/cmd/server/main.go.template +++ b/tools/backend-service/src/generators/service-gen/graphql-files/cmd/server/main.go.template @@ -22,6 +22,7 @@ import ( "libs/backend/boot" "libs/backend/cache" + "libs/backend/httpauth" ) // serviceName is the name of the microservice @@ -108,7 +109,7 @@ func run() error { }) params.Mux.Handle("/", playground.Handler("GraphQL playground", "/graphql")) - params.Mux.Handle("/graphql", srv) + params.Mux.Handle("/graphql", httpauth.AuthMiddleware(srv)) return nil }, From f57d108f6028661c37cb17b18f051b5d33b7691c Mon Sep 17 00:00:00 2001 From: Eric Zorn Date: Mon, 6 Jan 2025 18:30:47 -0500 Subject: [PATCH 2/2] v0.0.43 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ee3f19..2ef7cb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@career-cue/source", - "version": "0.0.42", + "version": "0.0.43", "license": "MIT", "engines": { "node": ">=22",