Golang authentication service
Small microservice to manage access to Users
Technical decisions
- I have limited authentication and is only used when removing a User resource. The middlewares will check if a user is authenticated and is removing resource of its own. Therefore, to remove a user through the API, you must authenticate with its credentials beforehand.
External dependencies
- I have used GORM to manage the database transactions.
- And go-chi to extend some HTTP service attributes.
Possible extensions or improvements
- When deploying to production, I would like to know if the number of requests for the service is very large, perhaps the tracing service can slow down performance.
- I would extend authentication to use roles, to allow users to have specific permissions.
- I have been used the attributes active and settings as a good practice but they are not completely functional and with some more time I would extend their functionality.
- Some things have not been tested, the functionality is (overall) correct but with a little more time I would have ensured 90%+ coverage.
- The migration method could be extended to use previous states of the database.
Data structure
Authentication
With password
The request must be sent form-encoded, and the response will be sent JSON encoded.
Request:
POST /api/oauth/login
Content-Type: application/x-www-form-urlencoded
grant_type=password
&[email protected]
&password=1234secret
Parameters:
- grant_type: Must be “password”.
- email: User’s email address.
- password: User’s password.
With refresh token
The request must be sent form-encoded, and the response will be sent JSON encoded.
A token request using a refresh token will return a new, current access token as well as a new refresh token, extending the lifetime of the user session and reducing chances of the user needing to login again to the system, as long as the user access the system frequently.
Request:
POST /api/oauth/login
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk
Parameters:
- grant_type: Must be “refresh_token”.
- refresh_token: A previously issued refresh_token.
User
A User resource represents a user of the system.
Fields:
Field | Type | Default | Description |
---|---|---|---|
id | int | User ID in the database. | |
active | bool | true | Whether the account is active. An inactive account is not able to login to the application, or perform any actions via the API. |
country | string | Country code on ISO 3166-1 format. | |
string | User email address. Used for user identification, login. Is a mandatory field and must be unique in the application. | ||
firstName, lastName | string | User name details. The first name is mandatory. | |
nickname | string | User nickname. | |
password | string | User password. Must be passed on create/update operations. It’s never returned on any read operations. | |
settings | string | {} | A string used to store user preferences like dark mode or similar profile data. |
Instructions to run the project
If the host operating system is MacOS:
make compose-mac
If it is Linux:
make compose-linux
On a first startup, the database should be initialised by running
go run ./cmd/admin/main.go migrate
After successful execution, the service should be running on port 8080:
Tracing can be found at:
Project tests can be run by typing:
make test
To explore what you can do with the Makefile:
make
API usage
The project has a Postman collection attached, which can be used to interact with the authentication/user service.
Packaging
├── cmd # Entrypoint
│ ├── admin # Admin (database) related tasks and x509 key creator for the auth service
│ └── api # Main API
├── doc # Documentation, images and helpful files
└── internal
├── errors # Utilities that make easier error handling throughout the project
├── handlers # HTTP layer
├── middleware
├── models # Business logic
├── schema # Framework for common database related tasks
└── web # Framework for common HTTP related tasks
Benchmarking
I have benchmarked the two most computationally expensive points of the API: The PUT method and authentication. Here are the results:
ali --body-file=./doc/assets/ali-update.json --method=PUT http://localhost:8080/api/users/1
Benchmark: 50 requests per second. Min: 12~ ms. Max: 120~ ms.
ali --rate=10 --method=POST http://localhost:8080/oauth/login/bench/
Benchmark: 10 requests per second. Min: 370~ ms. Max: 730~ ms.