wg-cc

module
v0.0.0-...-184bb4f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2023 License: MIT

README

Coding Exercise: Simple OAuth2 Server

Brief Description of Folders and Files Structure

Using the latest Go version, because it contains performance improvements, optimizations, and security patches.

Folders:

pkg - contains Go packages that can be used in other applications, if required

app - folder contains application business

cmd - contains the main Go files

Inside each subfolder of the app, the following files can be found:

handlers.go - contains the http server handlers, usually in a form of closure functions. The composition of handlers, services and repositories takes place in the main.go file.

requests.go - contains all the structs that represent the payloads the server accepts. The file can contain implementations of Unmarshal json, potential payload validation.

responses.go - contains all the structs that represent the server responses. Same as requests.go file, can contain implementation of Marshal.

service.go - the business logic for features that the application package has. Due to separation of concerns, it deals with all cryptographic operations, thus having transport doing transport things and repository doing storage related work.

repository.go - the storage layer, if it is the case. Instead of using a domain object, we expand all properties

Note that handlers take an Service interface, so we can write tests. The same goes for service, which accepts a Repository interface.

All interfaces are defined where they are used: even if all the files are in the same folder, it is a Go language best practice recommendation.

All compositions take place in the main application. The reason for this is due to the fact that we can have many flavors of applications (AWS lambda, microservice, monolith) that should compose the components and adapt to their respective conditions. For this reason, the Dockerfile sits next to the main.go file and each flavor of the application will have one.

I've used SQLite 3, but for scaling purposes we can use rqlite in the future.

External Packages Used

logrus - logging

jwt - JSON Web Tokens implementation, latest version (v5)

mux - router from Gorilla

handlers - CORS capabilities from Gorilla

http-swagger - Swagger documentation, facilitate demo

crypto - for bcrypt, avoid storing client_secret in plain text in the database

Internal Packages

In order to graceful shutdown, there are two packages runner and signal. For allowing creation of signing keys and adding clients, there is a very simple totp package.

Configuration

The following environment variables allow customization of the server:

  • JWT_TOKEN_DURATION - expiration of the tokens in hours. Default to 8 hours.

  • JWT_SIGNING_METHOD - default method used to sign tokens. Valid methods are RS384, RS512 and RS256. RS256 is default.

  • ALLOWED_CORS_URL - URLs of a possible frontend (SPA) application that would be allowed to use this server.

  • ALLOWED_CORS_HEADERS - All possible request headers that the SPA can use in requesting this server.

  • ALLOW_PPROF - If set to "true", opens routes to pprof the server.

  • APP_HTTP_PORT - Defaults to 8080, but we allow customization.

Kubernetes & Docker

build the container image, in the root of this project:

docker build . -t oauth-server:1.0.0 -f ./cmd/oauth2-server/Dockerfile

Running the built image:

docker run -p 8080:8080 oauth-server:1.0.0

You can now run integration test if you like.

Apply the deployment and service manifests using the following commands:

kubectl apply -f deployment.yaml

kubectl apply -f service.yaml

Use the following command to retrieve the external IP:

kubectl get services

Look for the EXTERNAL-IP column of the oauth2-server

Usage & Demo

In the database, there are three tables:

  • one which keeps clients by their id, secrets and key name which will be used to sign the JWT token
  • of course, a table which holds the RSA keys which are used in point 1
  • a table for holding the audit, the issues JWT tokens, which is being used when introspecting a token
  1. Start the server locally, as any normal Go language application. When the server starts, look for administration TOTP key message in the console and copy the value of the TOTP secret
  2. We need to create at least one private key and onboard one user. Point your browser towards Swagger page
  3. Go to this endpoint and complete the following: operation_type = create_key and totp = the code you've obtained in step 1. Give the key a valid name, by completing key_name form field.
  4. On the same endpoint, replace operation_type = create_client and provide key_name (signing key for that client), client_id and client_secret. Client secret will be stored encrypted in the database.
  5. Repeat for generating sigining keys and adding clients as needed. Note that client_id must be unique (no checks are done at the moment)
  6. You can use this endpoint to test jwt signing by providing the client id and secret declared on each client. The signing will be done using the key associated on onboarding.
  7. Test other endpoints as well, by using the same Swagger interface. Note that introspection and listing RSA keys require authentication (press Authorize button in the upper right and complete with Bearer +<JWT_TOKEN> obtained from the token route). Also, if you generate a new token (let's say for a different client), don't forget to update the Bearer value.

Final note

For any additional questions regarding this project, please feel free to contact me directly via email.

Directories

Path Synopsis
app
cmd
Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT This file was generated by swaggo/swag
Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT This file was generated by swaggo/swag
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL