From 73b47427e9cfd739fba5584d3de17fb062fa9089 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 11:37:24 -0800 Subject: [PATCH 1/9] improve oauth docs --- docs/oauth-authentication.md | 53 ++++++++---------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/docs/oauth-authentication.md b/docs/oauth-authentication.md index d526e0e3..2879de28 100644 --- a/docs/oauth-authentication.md +++ b/docs/oauth-authentication.md @@ -1,7 +1,5 @@ # OAuth Authentication -The ACM CSUF API uses Discord OAuth2 for authentication and authorization. This ensures that only authorized Discord server members with appropriate roles can access protected API endpoints. - ## Overview The API implements a role-based access control (RBAC) system that: @@ -14,7 +12,7 @@ The API implements a role-based access control (RBAC) system that: ### Server-Side: API Middleware -The API uses Discord OAuth2 middleware defined in [`internal/api/middleware/oauth.go`](../internal/api/middleware/oauth.go) to protect all `/v1` routes. +The API uses Discord OAuth2 middleware defined in [`internal/api/middleware/oauth.go`](../internal/api/middleware/oauth.go) to protect state-changing `/v1` routes. **How it works:** @@ -60,13 +58,13 @@ The CLI client (defined in [`utils/requests/request_with_auth.go`](../utils/requ └────┬────┘ └──────┬──────┘ │ │ │ 1. Start local callback server │ - │ on random port (e.g., :61234) │ + │ on hardcoded port (:61234) │ │ │ │ 2. Open browser with OAuth URL │ ├──────────────────────────────────────────> │ │ https://discord.com/oauth2/authorize │ │ ?client_id=... │ - │ &redirect_uri=http://localhost:54321 │ + │ &redirect_uri=http://localhost:61234 │ │ &scope=identify │ │ &response_type=code │ │ │ @@ -74,7 +72,7 @@ The CLI client (defined in [`utils/requests/request_with_auth.go`](../utils/requ │ │ │ 3. Discord redirects to callback │ │ <────────────────────────────────────────── │ - │ http://localhost:54321/?code=... │ + │ http://localhost:61234/?code=... │ │ │ │ 4. Exchange code for token │ ├──────────────────────────────────────────> │ @@ -108,23 +106,7 @@ See [`developer-docs/env-vars.md`](./env-vars.md) for the complete list, but OAu ## Development Mode -During development (`ENV=development`), authentication is bypassed: - -**API Server:** -```go -// Any request with this header will bypass OAuth -Authorization: Bearer dev-token -``` - -**CLI Client:** -```go -// Automatically uses dev-token when ENV=development -// No OAuth flow occurs, no tokens are exchanged -``` - -To test the actual OAuth flow during development, temporarily set `ENV=production` in your `.env` file. - -## Testing with OAuth +During development (`ENV=development`), authentication is bypassed by supplying `dev-token` to the `Authorization header`. The CLI will do this automatically. ### Using the CLI @@ -141,20 +123,17 @@ The CLI handles OAuth automatically: ### Using curl/xh with OAuth -If testing manually with `curl` or `xh`, you need a valid Discord access token: - +You need to manually pass the token when using a standard http client: ```bash # Development mode (no real auth needed) -xh :8080/v1/events Authorization:"Bearer dev-token" - -# Production mode (need real Discord token) -xh :8080/v1/events Authorization:"Bearer " +xh post :8080/v1/events --auth-type bearer --auth dev-token +# Or with short flags: +xh post :8080/v1/events -A bearer -a dev-token +# Or defining the header manually: +xh :8080/v1/events Authorization:'Bearer dev-token' ``` -To get a real Discord access token for testing: -1. Run the CLI once to complete the OAuth flow -2. Extract the token from `~/.config/acmcsuf-cli/token.json` -3. Use that token in your curl/xh commands +To get a real Discord access token for testing, run the OAuth flow with the CLI and extract the token from `~/.config/acmcsuf-cli/token.json` ### Token Expiry @@ -163,14 +142,6 @@ Discord access tokens expire after a period (typically 1 week). When a token exp **CLI**: The OAuth flow automatically re-runs on the next command **Manual testing**: You'll receive a `401 Unauthorized` response and need a new token -## Security Considerations - -1. **Never commit tokens**: Token files (`~/.config/acmcsuf-cli/token.json`) contain sensitive credentials -2. **HTTPS in production**: The API should only run behind HTTPS in production to protect tokens in transit -3. **Client secrets**: Keep `DISCORD_CLIENT_SECRET` secure and never commit to git -4. **Rate limiting**: The middleware caches role information for 5 minutes to respect Discord's rate limits -5. **Token storage**: CLI tokens are stored with `0600` permissions (read/write for owner only) - ## Role Configuration To add or modify roles, edit the `RoleMap` in [`internal/api/middleware/oauth.go`](../internal/api/middleware/oauth.go): From 1600e1a5f54bcdb689b8d7809291ec76a3ed97f1 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 11:52:12 -0800 Subject: [PATCH 2/9] update api-testing.md --- docs/api-testing.md | 63 +++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/docs/api-testing.md b/docs/api-testing.md index 75ab7358..d5ff49bb 100644 --- a/docs/api-testing.md +++ b/docs/api-testing.md @@ -1,72 +1,45 @@ # Testing the API -Once the api is running (via `air` or running it manually), you can use `xh` or `curl` to test the api from the command line. You probably already have `curl` installed, but `xh` is provided in the dev shell. -We recommend using `xh` as it is the more modern option. -If you prefer to use a GUI instead, Postman is a popular option. +Once the api is running (via `air` or running it manually), you can use `xh` or `curl` to test the api from the command line. We recommend using `xh` over `curl`, and it's provided in the dev shell. +If you prefer to use a GUI, Postman is a popular option. -## Using Swagger Documentation +## Using OpenAPI/Swagger Documentation -The API includes comprehensive Swagger documentation that provides an interactive interface for exploring and testing endpoints. When the server is running, you can access the Swagger UI at: +The API includes comprehensive OpenAPI2 (Swagger) documentation that provides an interactive interface for exploring and testing endpoints. When the server is running, you can access the Swagger UI at: ``` http://localhost:8080/swagger ``` -The Swagger documentation includes: -- Complete API endpoint documentation for all available routes -- Interactive forms to test API calls directly from the browser -- Request/response schemas and examples -- Parameter descriptions and validation rules - This is often the easiest way to explore the API and understand what endpoints are available without needing to dive into the source code. You can also use it to make test requests without needing to construct `curl` or `xh` commands manually. ## Using `xh` and `curl` -### Sending a GET request -The following requests will request an event called "event1" from the APIs `events` endpoint. You'll probably have to create this event yourself if you want to use this exact command (see the POST section below). -```sh -# assuming the server is running on localhost:8080 -xh :8080/v1/events/event1 - -# or with curl: -curl localhost:8080/v1/events/event1 -``` -Both `xh` and `curl` send a GET request by default, so you don't need to specify which method to use. -Note: `curl` won't give you formatted output by default, so it might be helpful to pipe to `jq` (also provided in dev shell) to make it look pretty. +### Sending a POST request +This creates a resource in the database that we can later query for with a GET request. +The OAuth2 middleware expects a `dev-token` passed with the Authorization middleware while in dev mode. See `oauth-authenticaion.md` for details. ```sh -curl localhost:8080/v1/events/event1 | jq +xh post :8080/v1/board/officers -A bearer -a dev-token \ +full_nae="Bob" \ +picture="example.com/picture.webp" \ +discord="discord.com/users/bob" \ +github="github.com/bob" \ +uuid="123" ``` - -### Sending a POST request +### Sending a GET request +This queries the database for the resource we just created: ```sh -xh POST :8080/v1/events \ -uuid="event1" \ -location="tsu" \ -start_at="1712851200000" \ -end_at="1712851200000" \ -is_all_day:=false \ -host="ACM" - -# same thing with curl: -curl -X POST localhost:8080/v1/events \ --H 'content-type: application/json' \ --H 'accept: application/json' \ --d '{"uuid":"event1","location":"tsu","start_at":"1712851200000","end_at":"1712851200000","is_all_day":false,"host":"ACM"}' +xh :8080/v1/board/officers/123 ``` -As you can see, `xh` provides a more concise way to do the same thing. +There are lots of other routes, check out the OpenAPI docs for more info. ### Using fixtures In the `fixtures` directory of this project, there's some JSON payloads that we can use for testing so we don't have to write them out each time. Feel free to create any that might be useful to yourself and/or the team. Here's an example using one to send a POST request: ```sh -xh POST :8080/v1/events @fixtures/event.json - -# same thing with curl: -curl -X POST localhost:8080/v1/events \ --H "Content-Type: application/json" \ --d @payload.json +xh post :8080/v1/events -A -a dev-token @fixtures/event_create.json ``` From e30caa9f636cc760ee0a5cd5a5b111ee3667e785 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 12:00:28 -0800 Subject: [PATCH 3/9] update project-structure.md --- docs/project-structure.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/project-structure.md b/docs/project-structure.md index 20c653ca..8900bb85 100644 --- a/docs/project-structure.md +++ b/docs/project-structure.md @@ -3,17 +3,18 @@ This document provides an overview of the project's directory structure and the responsibility of each main package. - `cmd/`: Main applications for the project. - - `acmcsuf-api/`: The main entry point for the API server. It handles command-line flags and graceful shutdown. - - `acmcsuf-cli/`: A command-line interface for interacting with the API. + - `acmcsuf-api/`: The main entry point for the API server. It handles command-line flags and graceful shutdown. + - `acmcsuf-cli/`: A command-line interface for interacting with the API. - `internal/`: Private application and library code. - - `api/`: Contains all the API server logic. - - `handlers/`: Gin handlers for processing HTTP requests. - - `routes/`: API route definitions. - - `services/`: Business logic for the API. - - `cli/`: Logic for the CLI application. - - `db/`: Database-related code, including schema, queries, and models. -- `developer-docs/`: Documentation for developers. -- `docs/`: Swagger/OpenAPI documentation. + - `api/`: Contains all the API server logic. + - `server.go`: Initializes and starts server. + - `routes/`: API route definitions. + - `handlers/`: Gin handlers for processing HTTP requests. + - `services/`: Business logic for the API. + - `middleware/`: Contains middleware like the rate limiter and OAuth implementation. + - `dbmodels/`: sqlc generated database models. Do not edit manually. + - `config/`: Loads environment vars and defines defaults. + - `cli/`: Logic for the CLI application. - `fixtures/`: JSON payloads for testing. - `nix/`: Nix dev shell and package definitions. - `utils/`: Shared utility functions. From 9f412c0a31229859e12f447291185526d868f928 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 12:04:42 -0800 Subject: [PATCH 4/9] remove cli docs from swagger docs --- internal/api/handlers/swagger.go | 2 - utils/api_description.md | 111 ------------------------------- utils/swagger_helper.go | 6 -- 3 files changed, 119 deletions(-) delete mode 100644 utils/api_description.md delete mode 100644 utils/swagger_helper.go diff --git a/internal/api/handlers/swagger.go b/internal/api/handlers/swagger.go index 627fbaa0..01a5fb91 100644 --- a/internal/api/handlers/swagger.go +++ b/internal/api/handlers/swagger.go @@ -2,7 +2,6 @@ package handlers import ( docs "github.com/acmcsufoss/api.acmcsuf.com/internal/api/docs" - "github.com/acmcsufoss/api.acmcsuf.com/utils" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" @@ -13,6 +12,5 @@ func NewSwaggerHandler() gin.HandlerFunc { docs.SwaggerInfo.Version = "1.0" docs.SwaggerInfo.Host = "localhost:8080" docs.SwaggerInfo.Schemes = []string{"http", "https"} - docs.SwaggerInfo.Description = utils.SwaggerDescription return ginSwagger.WrapHandler(swaggerFiles.Handler) } diff --git a/utils/api_description.md b/utils/api_description.md deleted file mode 100644 index 222e1fe4..00000000 --- a/utils/api_description.md +++ /dev/null @@ -1,111 +0,0 @@ -This is a documentation of the **acmcsuf API**. - ---- -# **acmcsuf-cli** -The command line interface tools provide a quick and easy way to test out the currently implemented routes. - -## **csuf events [command]** -Use this command to interact with event-related features. - -

Available Commands

-
    -
  • create – Create a new event
  • -
  • delete – Delete an event by ID
  • -
  • list – List all events
  • -
  • update – Update an event by ID
  • -
- -

Flags

-
    -
  • -h, --help – Show help for events
  • -
- -

Available Commands & Flags

-
    -
  • post – Post a new event -
      -
    • -d, --duration <string> – Duration (03:04:05)
    • -
    • -H, --host <string> – Host
    • -
    • -a, --isallday – All-day event
    • -
    • -l, --location <string> – Location
    • -
    • --port <string> – Port (default 8080)
    • -
    • -s, --startat <string> – Start time
    • -
    • --urlhost <string> – URL host (default 127.0.0.1)
    • -
    • -u, --uuid <string> – UUID
    • -
    -
  • -
  • get – Get events -
      -
    • --host <string> – Host (default 127.0.0.1)
    • -
    • --id <string> – Specific event ID
    • -
    • --port <string> – Port (default 8080)
    • -
    -
  • -
  • put – Update an event -
      -
    • --id <string>[REQUIRED] Event ID to update
    • -
    • -d, --duration <string> – End time
    • -
    • -H, --host <string> – Host
    • -
    • -a, --isallday – All-day event
    • -
    • -l, --location <string> – Location
    • -
    • --port <string> – Port (default 8080)
    • -
    • -s, --startat <string> – Start time
    • -
    • --urlhost <string> – URL host (default 127.0.0.1)
    • -
    • -u, --uuid <string> – UUID
    • -
    -
  • -
  • delete – Delete an event -
      -
    • --id <string>[REQUIRED] Event ID
    • -
    • --host <string> – Host (default 127.0.0.1)
    • -
    • --port <string> – Port (default 8080)
    • -
    -
  • -
-

-h, --help – Show help for events

- ---- -

csuf announcements [command]

-

Manage ACM CSUF's announcements through the CLI. Use csuf announcements [command] --help for more info on a specific command.

- -

Available Commands & Flags

-
    -
  • post – Post a new announcement -
      -
    • -a, --announceat <string> – Set this announcement's announce at
    • -
    • -c, --channelid <string> – Set this announcement's channel id
    • -
    • --host <string> – Custom host (default "127.0.0.1")
    • -
    • -m, --messageid <string> – Set this announcement's message id
    • -
    • --port <string> – Custom port (default "8080")
    • -
    • --uuid <string> – Set this announcement's id
    • -
    • -v, --visibility <string> – Set this announcement's visibility
    • -
    -
  • -
  • get – Get an announcement -
      -
    • --host <string> – Custom host (default "127.0.0.1")
    • -
    • --id <string> – Get a specific announcement by its id
    • -
    • --port <string> – Custom port (default "8080")
    • -
    -
  • -
  • put – Update an existing announcement by its id -
      -
    • --id <string>[REQUIRED] Announcement id to update
    • -
    • -a, --announceat <string> – Change this announcement's announce at
    • -
    • -c, --channelid <string> – Change this announcement's discord channel id
    • -
    • --host <string> – Custom host (default "127.0.0.1")
    • -
    • -m, --messageid <string> – Change this announcement's discord message id
    • -
    • --port <string> – Custom port (default "8080")
    • -
    • --uuid <string> – Change this announcement's uuid
    • -
    • -v, --visibility <string> – Change this announcement's visibility
    • -
    -
  • -
  • delete – Delete an announcement -
      -
    • --id <string>[REQUIRED] Delete an announcement by its id
    • -
    • --host <string> – Custom host (default "127.0.0.1")
    • -
    • --port <string> – Custom port (default "8080")
    • -
    -
  • -
-

-h, --help – Show help for announcements

diff --git a/utils/swagger_helper.go b/utils/swagger_helper.go deleted file mode 100644 index 3cabd98b..00000000 --- a/utils/swagger_helper.go +++ /dev/null @@ -1,6 +0,0 @@ -package utils - -import _ "embed" - -//go:embed api_description.md -var SwaggerDescription string From 0300465c76cddc8e2c3b02c084dafa533a6b54fa Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 12:05:12 -0800 Subject: [PATCH 5/9] rm redundant import name --- internal/api/handlers/swagger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/api/handlers/swagger.go b/internal/api/handlers/swagger.go index 01a5fb91..65822d09 100644 --- a/internal/api/handlers/swagger.go +++ b/internal/api/handlers/swagger.go @@ -1,7 +1,7 @@ package handlers import ( - docs "github.com/acmcsufoss/api.acmcsuf.com/internal/api/docs" + "github.com/acmcsufoss/api.acmcsuf.com/internal/api/docs" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" From a493f5647ebd6d60b8c9bf3742b51b0e31abbb61 Mon Sep 17 00:00:00 2001 From: Josh Holman Date: Fri, 6 Mar 2026 12:25:13 -0800 Subject: [PATCH 6/9] remove hardcoded host in swagger docs --- internal/api/handlers/swagger.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/api/handlers/swagger.go b/internal/api/handlers/swagger.go index 65822d09..68bd3117 100644 --- a/internal/api/handlers/swagger.go +++ b/internal/api/handlers/swagger.go @@ -1,16 +1,16 @@ package handlers import ( - "github.com/acmcsufoss/api.acmcsuf.com/internal/api/docs" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" + + "github.com/acmcsufoss/api.acmcsuf.com/internal/api/docs" ) func NewSwaggerHandler() gin.HandlerFunc { docs.SwaggerInfo.Title = "ACM CSUF API" docs.SwaggerInfo.Version = "1.0" - docs.SwaggerInfo.Host = "localhost:8080" docs.SwaggerInfo.Schemes = []string{"http", "https"} return ginSwagger.WrapHandler(swaggerFiles.Handler) } From 2d0f5f78820bff72ac89e72a03ee1a91b936d7a7 Mon Sep 17 00:00:00 2001 From: josh Date: Mon, 9 Mar 2026 09:30:33 -0700 Subject: [PATCH 7/9] update docs route --- docs/api-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-testing.md b/docs/api-testing.md index d5ff49bb..de981cd7 100644 --- a/docs/api-testing.md +++ b/docs/api-testing.md @@ -8,7 +8,7 @@ If you prefer to use a GUI, Postman is a popular option. The API includes comprehensive OpenAPI2 (Swagger) documentation that provides an interactive interface for exploring and testing endpoints. When the server is running, you can access the Swagger UI at: ``` -http://localhost:8080/swagger +http://localhost:8080/docs ``` This is often the easiest way to explore the API and understand what endpoints are available without needing to dive into the source code. You can also use it to make test requests without needing to construct `curl` or `xh` commands manually. From c45cd58b9d818e6cd6429a418e9ace54e1c49597 Mon Sep 17 00:00:00 2001 From: josh Date: Mon, 9 Mar 2026 09:33:27 -0700 Subject: [PATCH 8/9] add note about curl --- docs/api-testing.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api-testing.md b/docs/api-testing.md index de981cd7..8355d449 100644 --- a/docs/api-testing.md +++ b/docs/api-testing.md @@ -14,13 +14,14 @@ http://localhost:8080/docs This is often the easiest way to explore the API and understand what endpoints are available without needing to dive into the source code. You can also use it to make test requests without needing to construct `curl` or `xh` commands manually. ## Using `xh` and `curl` +These examples use `xh`, but you can get the equivalent `curl` command by appending the `--curl` flag to any example command. ### Sending a POST request This creates a resource in the database that we can later query for with a GET request. The OAuth2 middleware expects a `dev-token` passed with the Authorization middleware while in dev mode. See `oauth-authenticaion.md` for details. ```sh xh post :8080/v1/board/officers -A bearer -a dev-token \ -full_nae="Bob" \ +full_name="Bob" \ picture="example.com/picture.webp" \ discord="discord.com/users/bob" \ github="github.com/bob" \ From 91d9391e9cc65d60efd78f9d742337c5e841c357 Mon Sep 17 00:00:00 2001 From: josh Date: Mon, 9 Mar 2026 09:33:41 -0700 Subject: [PATCH 9/9] add newline --- docs/api-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-testing.md b/docs/api-testing.md index 8355d449..96a972aa 100644 --- a/docs/api-testing.md +++ b/docs/api-testing.md @@ -1,6 +1,6 @@ # Testing the API -Once the api is running (via `air` or running it manually), you can use `xh` or `curl` to test the api from the command line. We recommend using `xh` over `curl`, and it's provided in the dev shell. +Once the api is running (via `air` or running it manually), you can use `xh` or `curl` to test the api from the command line. We recommend using `xh` over `curl`, and it's provided in the dev shell. If you prefer to use a GUI, Postman is a popular option. ## Using OpenAPI/Swagger Documentation