Skip to content

refactor: rework oidc session storage#913

Open
steveiliop56 wants to merge 14 commits into
mainfrom
refactor/oidc-store
Open

refactor: rework oidc session storage#913
steveiliop56 wants to merge 14 commits into
mainfrom
refactor/oidc-store

Conversation

@steveiliop56
Copy link
Copy Markdown
Member

@steveiliop56 steveiliop56 commented May 31, 2026

Summary by CodeRabbit

  • New Features

    • Added PostgreSQL as a supported database driver option.
  • Refactor

    • Consolidated OpenID Connect storage into a single session model, simplifying session, token and userinfo handling for more reliable authentication and cleanup.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 38e0fb8f-114d-4157-a947-0a88da0e4c08

📥 Commits

Reviewing files that changed from the base of the PR and between 5caee88 and b3c152f.

📒 Files selected for processing (3)
  • internal/controller/oidc_controller.go
  • internal/service/oidc_service.go
  • sql/sqlite/oidc_schemas.sql
🚧 Files skipped from review as they are similar to previous changes (3)
  • sql/sqlite/oidc_schemas.sql
  • internal/controller/oidc_controller.go
  • internal/service/oidc_service.go

📝 Walkthrough

Walkthrough

Consolidates OIDC storage into a single oidc_sessions table and refactors the OIDC flow to use in-memory authorization-code caching with session-based token persistence; updates repositories, sqlc queries, migrations, controller wiring, service logic, and tests accordingly.

Changes

OIDC Sessions Consolidation

Layer / File(s) Summary
Environment documentation and database schema consolidation
.env.example, internal/assets/migrations/postgres/000002_oidc_rework.{up,down}.sql, internal/assets/migrations/sqlite/000010_oidc_rework.{up,down}.sql, sql/postgres/oidc_schemas.sql, sql/sqlite/oidc_schemas.sql
Env docs updated to mention postgres; migrations and schemas drop oidc_codes/oidc_tokens/oidc_userinfo and introduce a consolidated oidc_sessions table with token hashes, metadata, nonce, and userinfo_json.
SQL named queries for sessions
sql/postgres/oidc_queries.sql, sql/sqlite/oidc_queries.sql, sqlc.yml
Replaces previous code/token/userinfo query set with session-oriented named queries: Create/Get/Update/Delete and expired-session cleanup for oidc_sessions; sqlc overrides updated for nonce.
Repository models & interface
internal/repository/models.go, internal/repository/postgres/models.go, internal/repository/sqlite/models.go, internal/repository/store.go
Replaces OidcCode/OidcToken/OidcUserinfo types with OidcSession and updates the Store interface to session CRUD and lookup-by-token methods.
Postgres repository implementation
internal/repository/postgres/oidc_queries.sql.go, internal/repository/postgres/store.go
SQLC-generated Postgres queries and store wrappers implement session creation, lookup by sub/access/refresh token hash, update, delete-by-sub, and expired-session deletion.
SQLite repository implementation
internal/repository/sqlite/oidc_queries.sql.go, internal/repository/sqlite/store.go
SQLC-generated SQLite queries and store wrappers implement session creation, lookup by sub/access/refresh token hash, update, delete-by-sub, and expired-session deletion.
Memory repository & tests
internal/repository/memory/store.go, internal/repository/memory/oidc_queries.go, internal/repository/memory/memory_test.go
In-memory store replaces separate OIDC maps with oidcSessions and implements session CRUD with uniqueness checks; tests updated to validate session create/read/update/delete and expiry cleanup.
OIDC service refactor (cache + sessions)
internal/service/oidc_service.go
OIDCService removes gin.Context dependency, adds in-memory code cache and used-code tracking, shifts CreateCode/GetCodeEntry to cache, and persists tokens as oidc_sessions; refresh/update/load flows updated to use session JSON userinfo.
OIDC service tests
internal/service/oidc_service_test.go
Tests updated to build service.UserinfoResponse directly; scope strings changed to space-separated format; expectations adjusted for groups/address types.
OAuth service & extractor updates
internal/service/oauth_service.go, internal/service/oauth_extractors.go
Renames GitHub response type to GithubUserinfoResponse, introduces OAuthUserinfoExtractor type, and updates WithUserinfoExtractor signature.
OIDC controller endpoint wiring
internal/controller/oidc_controller.go
Authorize uses CreateCode/CreateSub; Token uses GetCodeEntry, IsCodeUsed, MarkCodeAsUsed, and session deletion on reuse; Userinfo uses GetSessionByToken and unmarshals userinfo_json, with scope/compile adapted.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • tinyauthapp/tinyauth#831: Prior work on the Store interface and OIDC persistence that this PR replaces with session-oriented methods.
  • tinyauthapp/tinyauth#777: Related scope/claims handling changes that interact with the updated CompileUserinfo and scope parsing.
  • tinyauthapp/tinyauth#829: Overlapping changes to the Authorize flow and user/sub handling in the controller.

Suggested reviewers

  • scottmckendry
  • Rycochet

"🧺🐇
I hopped through schemas, code, and tests,
Merged three tables into one for quiet rests.
Codes now cached and sessions stay near,
Tokens hashed, userinfo stored clear.
TinyAuth bound, the rabbit cheers!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: rework oidc session storage' accurately reflects the main change: a comprehensive refactoring of OIDC storage from separate code/token/userinfo tables to a consolidated session-based approach.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/oidc-store

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

@steveiliop56 steveiliop56 marked this pull request as ready for review June 1, 2026 09:27
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jun 1, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
internal/service/oidc_service.go (2)

311-315: 💤 Low value

Typo in variable name: codeCashcodeCache.

Minor naming inconsistency that could cause confusion during future maintenance.

✏️ Suggested fix
 	// Create caches
-	codeCash := NewCacheStore[AuthorizeCodeEntry](256)
+	codeCache := NewCacheStore[AuthorizeCodeEntry](256)
 	usedCode := NewCacheStore[UsedCodeEntry](256)
-	service.caches.code = codeCash
+	service.caches.code = codeCache
 	service.caches.usedCode = usedCode
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/oidc_service.go` around lines 311 - 315, The local variable
name "codeCash" is a typo; rename it to "codeCache" where it's declared and
assigned so it reads: codeCache := NewCacheStore[AuthorizeCodeEntry](256) and
then assign service.caches.code = codeCache; ensure any other references in this
scope use the new identifier; leave usedCode and service.caches.usedCode
unchanged.

571-571: 💤 Low value

Redundant strings.ReplaceAll for scope delimiter.

codeEntry.Scope is already space-separated (set in CreateCode at line 400 via strings.Join(..., " ")), so this comma-to-space replacement is unnecessary. The same pattern appears at line 650 in RefreshAccessToken.

✏️ Suggested fix
 	tokenResponse := TokenResponse{
 		AccessToken:  accessToken,
 		RefreshToken: refreshToken,
 		TokenType:    "Bearer",
 		ExpiresIn:    int64(service.config.Auth.SessionExpiry),
 		IDToken:      idToken,
-		Scope:        strings.ReplaceAll(codeEntry.Scope, ",", " "),
+		Scope:        codeEntry.Scope,
 	}

And at line 650:

-		Scope:        strings.ReplaceAll(entry.Scope, ",", " "),
+		Scope:        entry.Scope,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/oidc_service.go` at line 571, The strings.ReplaceAll(...,
",", " ") call that sets Scope when building the token response is redundant
because codeEntry.Scope is already built with spaces in CreateCode (via
strings.Join(..., " ")); remove the ReplaceAll and assign Scope directly from
codeEntry.Scope in the token creation path (and apply the same change in the
RefreshAccessToken code path where the same ReplaceAll is used) so both places
use codeEntry.Scope unchanged.
internal/assets/migrations/postgres/000002_oidc_rework.up.sql (1)

18-28: 💤 Low value

Redundant UNIQUE constraint on sub column.

PRIMARY KEY already enforces uniqueness, so the explicit UNIQUE constraint on sub is redundant.

Suggested fix
 CREATE TABLE IF NOT EXISTS "oidc_sessions" (
-    "sub" TEXT NOT NULL UNIQUE PRIMARY KEY,
+    "sub" TEXT NOT NULL PRIMARY KEY,
     "access_token_hash" TEXT NOT NULL UNIQUE,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/assets/migrations/postgres/000002_oidc_rework.up.sql` around lines
18 - 28, The "oidc_sessions" table defines the "sub" column with both UNIQUE and
PRIMARY KEY which is redundant; remove the explicit UNIQUE constraint from the
"sub" column definition so it remains only as PRIMARY KEY (leave other columns
and constraints unchanged) by editing the CREATE TABLE for oidc_sessions and
deleting the UNIQUE keyword on "sub".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/controller/oidc_controller.go`:
- Around line 334-335: The call to controller.oidc.DeleteSessionBySub in the
code-reuse branch currently ignores any returned error; update the handler so
the returned error is checked and logged (using controller.log.App.Warn() or
.Err()) while keeping the same response behavior. Locate the code around
controller.log.App.Warn().Msg("Code reuse detected") and the
controller.oidc.DeleteSessionBySub(c, usedCodeSub) call, capture the error value
from DeleteSessionBySub, and emit an appropriate log entry (including the error
and context like usedCodeSub) so failures to delete sessions are visible for
debugging.

In `@internal/service/oidc_service.go`:
- Around line 686-690: The deletion is calling the wrong query: Replace the call
to DeleteSession(ctx, entry.Sub) (which targets the non-OIDC sessions table
using UUID) with service.queries.DeleteOIDCSessionBySub(ctx, entry.Sub) so the
code deletes from oidc_sessions using the OIDC subject; update the call site in
the code that references DeleteSession to call DeleteOIDCSessionBySub and keep
passing entry.Sub and the same ctx.

In `@sql/sqlite/oidc_schemas.sql`:
- Line 9: The "nonce" column in the SQLite schema is missing a NOT NULL
constraint causing divergence from PostgreSQL; update the schema entry for the
"nonce" column (currently '"nonce" TEXT DEFAULT ""') to include NOT NULL so it
becomes '"nonce" TEXT NOT NULL DEFAULT ""', ensuring SQLite enforces the same
non-null behavior as PostgreSQL.

---

Nitpick comments:
In `@internal/assets/migrations/postgres/000002_oidc_rework.up.sql`:
- Around line 18-28: The "oidc_sessions" table defines the "sub" column with
both UNIQUE and PRIMARY KEY which is redundant; remove the explicit UNIQUE
constraint from the "sub" column definition so it remains only as PRIMARY KEY
(leave other columns and constraints unchanged) by editing the CREATE TABLE for
oidc_sessions and deleting the UNIQUE keyword on "sub".

In `@internal/service/oidc_service.go`:
- Around line 311-315: The local variable name "codeCash" is a typo; rename it
to "codeCache" where it's declared and assigned so it reads: codeCache :=
NewCacheStore[AuthorizeCodeEntry](256) and then assign service.caches.code =
codeCache; ensure any other references in this scope use the new identifier;
leave usedCode and service.caches.usedCode unchanged.
- Line 571: The strings.ReplaceAll(..., ",", " ") call that sets Scope when
building the token response is redundant because codeEntry.Scope is already
built with spaces in CreateCode (via strings.Join(..., " ")); remove the
ReplaceAll and assign Scope directly from codeEntry.Scope in the token creation
path (and apply the same change in the RefreshAccessToken code path where the
same ReplaceAll is used) so both places use codeEntry.Scope unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2dcda4c5-94aa-4539-962c-9882d880462a

📥 Commits

Reviewing files that changed from the base of the PR and between dac8445 and 5caee88.

📒 Files selected for processing (26)
  • .env.example
  • internal/assets/migrations/postgres/000002_oidc_rework.down.sql
  • internal/assets/migrations/postgres/000002_oidc_rework.up.sql
  • internal/assets/migrations/sqlite/000010_oidc_rework.down.sql
  • internal/assets/migrations/sqlite/000010_oidc_rework.up.sql
  • internal/controller/oidc_controller.go
  • internal/repository/memory/memory_test.go
  • internal/repository/memory/oidc_queries.go
  • internal/repository/memory/store.go
  • internal/repository/models.go
  • internal/repository/postgres/models.go
  • internal/repository/postgres/oidc_queries.sql.go
  • internal/repository/postgres/store.go
  • internal/repository/sqlite/models.go
  • internal/repository/sqlite/oidc_queries.sql.go
  • internal/repository/sqlite/store.go
  • internal/repository/store.go
  • internal/service/oauth_extractors.go
  • internal/service/oauth_service.go
  • internal/service/oidc_service.go
  • internal/service/oidc_service_test.go
  • sql/postgres/oidc_queries.sql
  • sql/postgres/oidc_schemas.sql
  • sql/sqlite/oidc_queries.sql
  • sql/sqlite/oidc_schemas.sql
  • sqlc.yml

Comment thread internal/controller/oidc_controller.go Outdated
Comment thread internal/service/oidc_service.go
Comment thread sql/sqlite/oidc_schemas.sql Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant