Skip to content

Feature/keycloak integration#18

Open
Muniya-64bit wants to merge 40 commits into
mainfrom
feature/keycloak_integration
Open

Feature/keycloak integration#18
Muniya-64bit wants to merge 40 commits into
mainfrom
feature/keycloak_integration

Conversation

@Muniya-64bit

Copy link
Copy Markdown
Contributor

No description provided.

- Fixed wrapper issues in code
- Added a scroll bar to code uploader
- Addded connet button
- So we can setup file manager easily in that way
- UI fixes in REPL
- Disconneted issue in ESP32
- Issues was in REPL conncetion lost while tab switching between UPLOADER and REPL
- Also colour changes in REPL
- currently can view files in esp32
- currently can download each file separatly
- Now user can view file content from esp32
- users can access each by swithcing tabs
- Users an get multiple tabs and code
- Also file manager view files using code editor
-
- Setup  a delay in file manager view ( enugh time to realese lock)
Muniya-64bit and others added 10 commits March 20, 2026 00:25
@vercel

vercel Bot commented May 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nexus-tools-obo-blocks Error Error May 10, 2026 4:49am
nexus-tools-obo-code Error Error May 10, 2026 4:49am
nexus-tools-obo-playground Error Error May 10, 2026 4:49am

@Muniya-64bit Muniya-64bit requested a review from AnasSAV May 10, 2026 04:49
@AnasSAV

AnasSAV commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

PR #18: Feature/Keycloak Integration

This PR wires up Keycloak/NextAuth across all three apps via a shared @nexus-tools/auth package, and separately refactors the ESP32 serial layer into a singleton stream manager. The ESP32 changes look solid. The auth layer has several correctness and security issues that should be fixed before merge.

9 findings: 2 Critical · 3 High · 4 Medium


Critical

1. Keycloak roles never extracted - every user permanently gets role: "user"
packages/auth/src/config.ts:50

The jwt callback signature is async jwt({ token, account })- it never destructures profile, and the initial sign-in block never writes token.roles. The session callback reads (token.roles as string[])?.includes("admin"), which is always undefined, so every user gets role: "user" and roles: []. Admin access is permanently broken for all users.

Fix: accept profile in the JWT callback and extract realm roles:

async jwt({ token, account, profile }) {
  if (account) {
    // ... existing assignments ...
    const p = profile as any;
    token.roles = p?.realm_access?.roles ?? p?.roles ?? [];
  }
}

2. Hardcoded client secret fallback "124" committed to source
packages/auth/src/config.ts:13

const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET || "124" - any environment where the env var is missing silently uses "124" as the OAuth client secret. The value is now permanent in git history. If "124" is the actual Keycloak secret, it should be rotated immediately.

Fix: fail fast instead of falling back:

const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET;
if (!clientSecret) throw new Error("KEYCLOAK_CLIENT_SECRET env var is required");

High

3. Token refresh failure swallowed silently - no error flag, infinite retry
packages/auth/src/config.ts:82–95

When the Keycloak refresh endpoint returns non-2xx (expired refresh token, revoked session, network failure), the code logs the error and return token — the stale token with its old expiresAt still in the past. token.error is never set. Because expiresAt remains expired, the refresh condition fires on every subsequent JWT callback call, creating a thundering herd against Keycloak. Meanwhile session.error is always undefined, so clients can't detect the failure and users stay "authenticated" while all API calls return 401.

Fix — standard NextAuth pattern:

if (!response.ok) {
  return { ...token, error: "RefreshAccessTokenError" };
}
// same in the catch block

Then check session.error === "RefreshAccessTokenError" on the client to redirect to login.


4. updateAge === maxAge makes proactive refresh unreachable
packages/auth/src/config.ts:43–44

Both session.maxAge and session.updateAge are 60 * 60 (3600s). NextAuth only re-invokes the JWT callback when updateAge seconds have elapsed since the last update. With them equal, the session expires before NextAuth ever calls jwt() again — the entire 5-minute pre-expiry refresh branch is dead code under normal usage. Tokens expire silently.

Fix: set updateAge to a fraction of maxAge, e.g. 60 * 10 (10 minutes).


5. Refresh token sent to the browser in the session object
packages/auth/src/config.ts:109

The session callback includes refreshToken: token.refreshToken as string, which NextAuth serialises and serves via GET /api/auth/session - a plain JSON endpoint readable by any JavaScript on the page. Refresh tokens are long-lived and should never leave the server. Any XSS vulnerability (now or in the future) can exfiltrate this token and maintain persistent account access indefinitely.

Fix: remove refreshToken (and idToken unless explicitly needed) from the session callback return value. The useRefreshToken hook also re-exports session.refreshToken to consumer components — that field should be removed from the hook's return value too.


Medium

6. fetchWithAuth 401 retry is a no-op - retries with the same expired token
packages/utils/src/api/fetchWithAuth.ts:40–51

On a 401, the code fetches GET /api/auth/session (a read-only endpoint) then calls getSession() again. This does not force a Keycloak token refresh — both calls return the same cached session. The retry sends the same expired Bearer token and receives another 401, then hard-navigates via window.location.href = "/login" without clearing the NextAuth session cookie, which can cause a redirect loop if the Keycloak session is also expired.


7. Dead [...auth].ts route files with module-level side effects
apps/obo-code/src/app/api/auth/[...auth].ts · apps/obo-blocks/src/app/api/auth/[...auth].ts

In Next.js App Router, only route.ts files serve as route handlers. These [...auth].ts files are never invoked as routes but are compiled by Next.js, firing two module-level console.log calls and running getAuthConfig() a second time on every cold start. The real handler is the sibling [...nextauth]/route.ts. Both files should be deleted.


8. cookies.txt committed to the repository
cookies.txt:1

A libcurl Netscape-format cookie store is now tracked in version control. If a developer runs curl --cookie-jar cookies.txt against the auth endpoints, active Keycloak session cookies will be written into this file and committed.

Fix: git rm --cached cookies.txt and add cookies.txt to .gitignore.


9. remotePatterns accidentally cleared in next.config.js
apps/obo-code/next.config.js:10

remotePatterns was changed from [{ protocol: "https", hostname: "skulpt.org" }] to [], dropping the previously allowed hostname. Looks like an accidental wipe during the transpilePackages edit. Any component using <Image> with a skulpt.org src will get a 400 from the Next.js image optimizer at runtime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants