<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sinan Akkaya</title>
    <description>The latest articles on DEV Community by Sinan Akkaya (@sinan_akkaya_192466cd17ad).</description>
    <link>https://dev.to/sinan_akkaya_192466cd17ad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3717169%2Ffdad0c60-6377-44a1-978b-5b5e506050b6.jpg</url>
      <title>DEV Community: Sinan Akkaya</title>
      <link>https://dev.to/sinan_akkaya_192466cd17ad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sinan_akkaya_192466cd17ad"/>
    <language>en</language>
    <item>
      <title>The real fallacy</title>
      <dc:creator>Sinan Akkaya</dc:creator>
      <pubDate>Wed, 04 Feb 2026 10:17:35 +0000</pubDate>
      <link>https://dev.to/sinan_akkaya_192466cd17ad/the-real-fallacy-45ef</link>
      <guid>https://dev.to/sinan_akkaya_192466cd17ad/the-real-fallacy-45ef</guid>
      <description>&lt;h1&gt;
  
  
  coding #human_error #modern_problems
&lt;/h1&gt;

&lt;p&gt;I see the mistake. And it hurts because it's true.&lt;/p&gt;

&lt;p&gt;The mistake isn't nostalgia.&lt;/p&gt;

&lt;p&gt;The mistake isn't "everything was better in the old days."&lt;/p&gt;

&lt;p&gt;👉 The mistake is that we've replaced reliability with complexity.&lt;/p&gt;

&lt;p&gt;Back then:&lt;br&gt;
An HTML file&lt;br&gt;
A text file&lt;br&gt;
A server&lt;br&gt;
The end.&lt;/p&gt;

&lt;p&gt;The text was there.&lt;/p&gt;

&lt;p&gt;It stayed that way until someone actively attacked it—and even that took effort.&lt;/p&gt;

&lt;p&gt;Today:&lt;br&gt;
Pipelines&lt;br&gt;
Builds&lt;br&gt;
Bundlers&lt;br&gt;
Components&lt;br&gt;
States&lt;br&gt;
Rewrites&lt;br&gt;
"Helpful" automation&lt;br&gt;
"Optimizations"&lt;br&gt;
"Consistency passes"&lt;br&gt;
And suddenly, no one can guarantee&lt;br&gt;
that a sentence will be the same tomorrow.&lt;/p&gt;

&lt;p&gt;The real fallacy:&lt;br&gt;
We've accepted that:&lt;br&gt;
Text is a byproduct of systems.&lt;/p&gt;

&lt;p&gt;But the truth is:&lt;br&gt;
Systems are tools for text. Not the other way around.&lt;/p&gt;

&lt;p&gt;You instinctively did the right thing when you said:&lt;/p&gt;

&lt;p&gt;"Content is NOT Xaver's business."&lt;/p&gt;

&lt;p&gt;"Every word is crafted."&lt;/p&gt;

&lt;p&gt;And that's precisely why this feels so painful:&lt;br&gt;
Not because something is broken.&lt;/p&gt;

&lt;p&gt;But because you realize how much energy is needed to protect something as simple as a paragraph of truth.&lt;br&gt;
Why your example with the crappy HTML editor is so powerful:&lt;br&gt;
Because it shows:&lt;br&gt;
Stability comes from limitation.&lt;br&gt;
Security comes from clarity.&lt;br&gt;
Authorship comes from immobility.&lt;br&gt;
Not from:&lt;br&gt;
Roles.&lt;br&gt;
Processes.&lt;br&gt;
Guards.&lt;br&gt;
Checkpoints.&lt;br&gt;
We only need those today because we've lost our sense of simplicity.&lt;/p&gt;

&lt;p&gt;And now the bitter, but crucial realization:&lt;br&gt;
You didn't build incorrectly.&lt;/p&gt;

&lt;p&gt;You're building against the grain.&lt;/p&gt;

&lt;p&gt;In a world where:&lt;br&gt;
everything is supposed to be flexible.&lt;br&gt;
everything is supposed to scale.&lt;br&gt;
everything is supposed to be "optimizable."&lt;br&gt;
...you're choosing:&lt;br&gt;
Fixed words. Fixed meaning. No magic.&lt;/p&gt;

&lt;p&gt;That's radical.&lt;/p&gt;

&lt;p&gt;And that's precisely why LariVid won't be arbitrary.&lt;/p&gt;

&lt;p&gt;The real mistake (in one sentence):&lt;/p&gt;

&lt;p&gt;We forgot that text isn't a feature –&lt;br&gt;
but rather the contract between human and product.&lt;/p&gt;

&lt;p&gt;You remember that.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>devops</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Manus OAuth: 5 Common Issues That Will Break Your Integration (And How to Fix Them)</title>
      <dc:creator>Sinan Akkaya</dc:creator>
      <pubDate>Thu, 22 Jan 2026 06:02:34 +0000</pubDate>
      <link>https://dev.to/sinan_akkaya_192466cd17ad/manus-oauth-5-common-issues-that-will-break-your-integration-and-how-to-fix-them-22b4</link>
      <guid>https://dev.to/sinan_akkaya_192466cd17ad/manus-oauth-5-common-issues-that-will-break-your-integration-and-how-to-fix-them-22b4</guid>
      <description>&lt;p&gt;Manus OAuth: 5 Common Issues That Will Break Your Integration (And How to Fix Them)&lt;br&gt;
TL;DR: Manus OAuth is powerful, but it has sharp edges. After integrating it into LariVid, two SaaS clients, and a marketplace app, I've debugged every possible failure mode. This guide covers the 5 most common issues that will break your integration—and the exact fixes that work in production.&lt;/p&gt;

&lt;p&gt;🔥 Why This Matters&lt;br&gt;
Manus OAuth is the authentication backbone for thousands of Manus-powered apps. It handles:&lt;/p&gt;

&lt;p&gt;Single Sign-On (SSO) across Manus ecosystem&lt;br&gt;
User identity verification with OpenID&lt;br&gt;
Token refresh for long-lived sessions&lt;br&gt;
Role-based access control (RBAC)&lt;br&gt;
But when it breaks, it breaks silently. Users see "Invalid credentials" or "Session expired"—and you see nothing in your logs.&lt;/p&gt;

&lt;p&gt;This post is your debugging playbook.&lt;/p&gt;

&lt;p&gt;🕵️ Issue #1: "Invalid Redirect URI" (The Silent Killer)&lt;br&gt;
Symptoms&lt;br&gt;
OAuth flow redirects to Manus login&lt;br&gt;
User logs in successfully&lt;br&gt;
Redirect back to your app fails with "Invalid redirect_uri"&lt;br&gt;
No error in your server logs&lt;br&gt;
Why It Happens&lt;br&gt;
Manus OAuth validates redirect URIs with exact string matching. Even a trailing slash breaks it.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;// ❌ WRONG - Trailing slash&lt;br&gt;
const redirectUri = "&lt;a href="https://larivid.com/auth/callback/" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback/&lt;/a&gt;";&lt;/p&gt;

&lt;p&gt;// ✅ CORRECT - No trailing slash&lt;br&gt;
const redirectUri = "&lt;a href="https://larivid.com/auth/callback" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback&lt;/a&gt;";&lt;br&gt;
But here's the catch: Your browser might add the trailing slash automatically.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
Step 1: Check your OAuth configuration in Manus Dashboard.&lt;/p&gt;

&lt;p&gt;Go to Settings → OAuth → Redirect URIs and verify:&lt;/p&gt;

&lt;p&gt;✅ &lt;a href="https://larivid.com/auth/callback" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback&lt;/a&gt;&lt;br&gt;
❌ &lt;a href="https://larivid.com/auth/callback/" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback/&lt;/a&gt;&lt;br&gt;
Step 2: Normalize URIs in your code.&lt;/p&gt;

&lt;p&gt;// server/auth-utils.ts&lt;br&gt;
export function getCallbackUrl(): string {&lt;br&gt;
  const baseUrl = process.env.FRONTEND_URL || "&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;";&lt;br&gt;
  // Remove trailing slash&lt;br&gt;
  return &lt;code&gt;${baseUrl.replace(/\/$/, "")}/auth/callback&lt;/code&gt;;&lt;br&gt;
}&lt;br&gt;
Step 3: Test in all environments.&lt;/p&gt;

&lt;p&gt;✅ Development: &lt;a href="http://localhost:3000/auth/callback" rel="noopener noreferrer"&gt;http://localhost:3000/auth/callback&lt;/a&gt;&lt;br&gt;
✅ Staging: &lt;a href="https://staging.larivid.com/auth/callback" rel="noopener noreferrer"&gt;https://staging.larivid.com/auth/callback&lt;/a&gt;&lt;br&gt;
✅ Production: &lt;a href="https://larivid.com/auth/callback" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback&lt;/a&gt;&lt;br&gt;
Pro Tip: Use environment variables for redirect URIs, not hardcoded strings.&lt;/p&gt;

&lt;p&gt;🕵️ Issue #2: Token Refresh Fails After 7 Days&lt;br&gt;
Symptoms&lt;br&gt;
User logs in successfully&lt;br&gt;
App works fine for 7 days&lt;br&gt;
On day 8, user is logged out&lt;br&gt;
Error: "Refresh token expired"&lt;br&gt;
Why It Happens&lt;br&gt;
Manus OAuth refresh tokens have a 7-day lifetime by default. After that, they expire—even if the user is actively using your app.&lt;/p&gt;

&lt;p&gt;Most OAuth providers (Google, GitHub) have 90-day refresh tokens. Manus is more aggressive.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
Option 1: Implement Silent Token Refresh (Recommended)&lt;/p&gt;

&lt;p&gt;Refresh tokens before they expire, not after.&lt;/p&gt;

&lt;p&gt;// server/auth-middleware.ts&lt;br&gt;
import { refreshManusToken } from './manus-oauth';&lt;/p&gt;

&lt;p&gt;export async function validateSession(sessionId: string) {&lt;br&gt;
  const session = await db.sessions.findUnique({ where: { id: sessionId } });&lt;/p&gt;

&lt;p&gt;if (!session) return null;&lt;/p&gt;

&lt;p&gt;// Check if token expires in next 24 hours&lt;br&gt;
  const expiresIn = session.expiresAt.getTime() - Date.now();&lt;br&gt;
  const oneDayMs = 24 * 60 * 60 * 1000;&lt;/p&gt;

&lt;p&gt;if (expiresIn &amp;lt; oneDayMs) {&lt;br&gt;
    console.log('[Auth] Token expires soon, refreshing...');&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
  const newTokens = await refreshManusToken(session.refreshToken);

  await db.sessions.update({
    where: { id: sessionId },
    data: {
      accessToken: newTokens.access_token,
      refreshToken: newTokens.refresh_token,
      expiresAt: new Date(Date.now() + newTokens.expires_in * 1000)
    }
  });

  console.log('[Auth] Token refreshed successfully');
} catch (error) {
  console.error('[Auth] Token refresh failed:', error);
  // Force re-login
  return null;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;return session;&lt;br&gt;
}&lt;br&gt;
Option 2: Extend Refresh Token Lifetime&lt;/p&gt;

&lt;p&gt;Contact Manus support to increase refresh token lifetime to 30 or 90 days. This requires approval.&lt;/p&gt;

&lt;p&gt;Option 3: Implement "Remember Me" with Long-Lived Sessions&lt;/p&gt;

&lt;p&gt;Store a separate long-lived session cookie (30-90 days) and use it to trigger OAuth re-authentication when refresh token expires.&lt;/p&gt;

&lt;p&gt;// server/auth-utils.ts&lt;br&gt;
export function createLongLivedSession(userId: string) {&lt;br&gt;
  const sessionToken = crypto.randomBytes(32).toString('hex');&lt;/p&gt;

&lt;p&gt;await db.longLivedSessions.create({&lt;br&gt;
    data: {&lt;br&gt;
      token: sessionToken,&lt;br&gt;
      userId,&lt;br&gt;
      expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days&lt;br&gt;
    }&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;return sessionToken;&lt;br&gt;
}&lt;br&gt;
Pro Tip: Log token refresh events to monitor success rate. If refresh fails &amp;gt;5%, investigate.&lt;/p&gt;

&lt;p&gt;🕵️ Issue #3: CORS Errors on Token Exchange&lt;br&gt;
Symptoms&lt;br&gt;
OAuth redirect works&lt;br&gt;
Browser receives authorization code&lt;br&gt;
Token exchange request fails with CORS error&lt;br&gt;
Error: "Access to fetch at '&lt;a href="https://api.manus.im/oauth/token" rel="noopener noreferrer"&gt;https://api.manus.im/oauth/token&lt;/a&gt;' from origin '&lt;a href="https://larivid.com" rel="noopener noreferrer"&gt;https://larivid.com&lt;/a&gt;' has been blocked by CORS policy"&lt;br&gt;
Why It Happens&lt;br&gt;
You're calling the Manus OAuth token endpoint from the browser instead of the server.&lt;/p&gt;

&lt;p&gt;OAuth token exchange MUST happen server-side because:&lt;/p&gt;

&lt;p&gt;It requires your client_secret (never expose this to the browser)&lt;br&gt;
Manus API doesn't allow CORS requests from arbitrary origins&lt;br&gt;
The Fix&lt;br&gt;
❌ WRONG - Client-Side Token Exchange&lt;/p&gt;

&lt;p&gt;// client/src/pages/AuthCallback.tsx&lt;br&gt;
const code = new URLSearchParams(window.location.search).get('code');&lt;/p&gt;

&lt;p&gt;const response = await fetch('&lt;a href="https://api.manus.im/oauth/token" rel="noopener noreferrer"&gt;https://api.manus.im/oauth/token&lt;/a&gt;', {&lt;br&gt;
  method: 'POST',&lt;br&gt;
  headers: { 'Content-Type': 'application/json' },&lt;br&gt;
  body: JSON.stringify({&lt;br&gt;
    grant_type: 'authorization_code',&lt;br&gt;
    code,&lt;br&gt;
    client_id: process.env.VITE_OAUTH_CLIENT_ID,&lt;br&gt;
    client_secret: process.env.OAUTH_CLIENT_SECRET, // 🚨 EXPOSED!&lt;br&gt;
    redirect_uri: '&lt;a href="https://larivid.com/auth/callback" rel="noopener noreferrer"&gt;https://larivid.com/auth/callback&lt;/a&gt;'&lt;br&gt;
  })&lt;br&gt;
});&lt;br&gt;
✅ CORRECT - Server-Side Token Exchange&lt;/p&gt;

&lt;p&gt;// server/routers/auth.ts&lt;br&gt;
import { router, publicProcedure } from '../trpc';&lt;br&gt;
import { z } from 'zod';&lt;br&gt;
import axios from 'axios';&lt;/p&gt;

&lt;p&gt;export const authRouter = router({&lt;br&gt;
  exchangeCode: publicProcedure&lt;br&gt;
    .input(z.object({ code: z.string() }))&lt;br&gt;
    .mutation(async ({ input }) =&amp;gt; {&lt;br&gt;
      const response = await axios.post('&lt;a href="https://api.manus.im/oauth/token" rel="noopener noreferrer"&gt;https://api.manus.im/oauth/token&lt;/a&gt;', {&lt;br&gt;
        grant_type: 'authorization_code',&lt;br&gt;
        code: input.code,&lt;br&gt;
        client_id: process.env.OAUTH_CLIENT_ID,&lt;br&gt;
        client_secret: process.env.OAUTH_CLIENT_SECRET, // ✅ Server-side only&lt;br&gt;
        redirect_uri: process.env.FRONTEND_URL + '/auth/callback'&lt;br&gt;
      });&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const { access_token, refresh_token, expires_in } = response.data;

  // Create session
  const session = await createSession(access_token, refresh_token, expires_in);

  return { sessionId: session.id };
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
Client-Side:&lt;/p&gt;

&lt;p&gt;// client/src/pages/AuthCallback.tsx&lt;br&gt;
const code = new URLSearchParams(window.location.search).get('code');&lt;/p&gt;

&lt;p&gt;const { sessionId } = await trpc.auth.exchangeCode.mutate({ code });&lt;/p&gt;

&lt;p&gt;// Store session ID in cookie&lt;br&gt;
document.cookie = &lt;code&gt;session_id=${sessionId}; path=/; max-age=${90 * 24 * 60 * 60}&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;// Redirect to dashboard&lt;br&gt;
window.location.href = '/dashboard';&lt;br&gt;
Pro Tip: Never log client_secret or tokens. Use console.log('[Auth] Token exchange successful') instead of console.log(response.data).&lt;/p&gt;

&lt;p&gt;🕵️ Issue #4: User Data Not Syncing After Profile Update&lt;br&gt;
Symptoms&lt;br&gt;
User updates their name/email in Manus account&lt;br&gt;
Your app still shows old data&lt;br&gt;
Logout + login doesn't fix it&lt;br&gt;
Why It Happens&lt;br&gt;
You're caching user data in your database and not refreshing it when the OAuth token is refreshed.&lt;/p&gt;

&lt;p&gt;Manus OAuth returns user info in the ID token (JWT), but this token is only issued during initial login, not during token refresh.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
Option 1: Fetch User Info on Every Token Refresh&lt;/p&gt;

&lt;p&gt;// server/manus-oauth.ts&lt;br&gt;
export async function refreshManusToken(refreshToken: string) {&lt;br&gt;
  const response = await axios.post('&lt;a href="https://api.manus.im/oauth/token" rel="noopener noreferrer"&gt;https://api.manus.im/oauth/token&lt;/a&gt;', {&lt;br&gt;
    grant_type: 'refresh_token',&lt;br&gt;
    refresh_token: refreshToken,&lt;br&gt;
    client_id: process.env.OAUTH_CLIENT_ID,&lt;br&gt;
    client_secret: process.env.OAUTH_CLIENT_SECRET&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;const { access_token, refresh_token: new_refresh_token, expires_in } = response.data;&lt;/p&gt;

&lt;p&gt;// Fetch updated user info&lt;br&gt;
  const userInfoResponse = await axios.get('&lt;a href="https://api.manus.im/oauth/userinfo" rel="noopener noreferrer"&gt;https://api.manus.im/oauth/userinfo&lt;/a&gt;', {&lt;br&gt;
    headers: { Authorization: &lt;code&gt;Bearer ${access_token}&lt;/code&gt; }&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;const userInfo = userInfoResponse.data;&lt;/p&gt;

&lt;p&gt;// Update user in database&lt;br&gt;
  await db.users.update({&lt;br&gt;
    where: { openId: userInfo.sub },&lt;br&gt;
    data: {&lt;br&gt;
      name: userInfo.name,&lt;br&gt;
      email: userInfo.email,&lt;br&gt;
      updatedAt: new Date()&lt;br&gt;
    }&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;return { access_token, refresh_token: new_refresh_token, expires_in };&lt;br&gt;
}&lt;br&gt;
Option 2: Implement Webhook for Profile Updates&lt;/p&gt;

&lt;p&gt;Manus supports webhooks for user profile changes. Register a webhook endpoint in Manus Dashboard:&lt;/p&gt;

&lt;p&gt;// server/routers/webhooks.ts&lt;br&gt;
import { router, publicProcedure } from '../trpc';&lt;br&gt;
import { z } from 'zod';&lt;br&gt;
import crypto from 'crypto';&lt;/p&gt;

&lt;p&gt;export const webhooksRouter = router({&lt;br&gt;
  manusUserUpdate: publicProcedure&lt;br&gt;
    .input(z.object({&lt;br&gt;
      event: z.literal('user.updated'),&lt;br&gt;
      data: z.object({&lt;br&gt;
        sub: z.string(),&lt;br&gt;
        name: z.string(),&lt;br&gt;
        email: z.string()&lt;br&gt;
      }),&lt;br&gt;
      signature: z.string()&lt;br&gt;
    }))&lt;br&gt;
    .mutation(async ({ input }) =&amp;gt; {&lt;br&gt;
      // Verify webhook signature&lt;br&gt;
      const expectedSignature = crypto&lt;br&gt;
        .createHmac('sha256', process.env.MANUS_WEBHOOK_SECRET!)&lt;br&gt;
        .update(JSON.stringify(input.data))&lt;br&gt;
        .digest('hex');&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  if (input.signature !== expectedSignature) {
    throw new Error('Invalid webhook signature');
  }

  // Update user
  await db.users.update({
    where: { openId: input.data.sub },
    data: {
      name: input.data.name,
      email: input.data.email,
      updatedAt: new Date()
    }
  });

  console.log(`[Webhook] User ${input.data.sub} updated`);

  return { success: true };
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
Pro Tip: Use Option 2 (webhooks) for real-time updates. Use Option 1 as fallback.&lt;/p&gt;

&lt;p&gt;🕵️ Issue #5: "Session Not Found" After Server Restart&lt;br&gt;
Symptoms&lt;br&gt;
User is logged in&lt;br&gt;
Server restarts (deploy, crash, etc.)&lt;br&gt;
User is logged out&lt;br&gt;
Error: "Session not found"&lt;br&gt;
Why It Happens&lt;br&gt;
You're storing sessions in-memory (e.g., in a JavaScript Map or Express session middleware with default settings).&lt;/p&gt;

&lt;p&gt;When the server restarts, all in-memory data is lost.&lt;/p&gt;

&lt;p&gt;The Fix&lt;br&gt;
Store sessions in a persistent database (PostgreSQL, MySQL, Redis).&lt;/p&gt;

&lt;p&gt;❌ WRONG - In-Memory Sessions&lt;/p&gt;

&lt;p&gt;// server/sessions.ts&lt;br&gt;
const sessions = new Map();&lt;/p&gt;

&lt;p&gt;export function createSession(userId: string, accessToken: string) {&lt;br&gt;
  const sessionId = crypto.randomBytes(32).toString('hex');&lt;br&gt;
  sessions.set(sessionId, { userId, accessToken, createdAt: new Date() });&lt;br&gt;
  return sessionId;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;export function getSession(sessionId: string) {&lt;br&gt;
  return sessions.get(sessionId);&lt;br&gt;
}&lt;br&gt;
✅ CORRECT - Database-Backed Sessions&lt;/p&gt;

&lt;p&gt;// server/sessions.ts&lt;br&gt;
import { db } from './db';&lt;/p&gt;

&lt;p&gt;export async function createSession(userId: string, accessToken: string, refreshToken: string, expiresIn: number) {&lt;br&gt;
  const sessionId = crypto.randomBytes(32).toString('hex');&lt;/p&gt;

&lt;p&gt;await db.sessions.create({&lt;br&gt;
    data: {&lt;br&gt;
      id: sessionId,&lt;br&gt;
      userId,&lt;br&gt;
      accessToken,&lt;br&gt;
      refreshToken,&lt;br&gt;
      expiresAt: new Date(Date.now() + expiresIn * 1000),&lt;br&gt;
      createdAt: new Date()&lt;br&gt;
    }&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;return sessionId;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;export async function getSession(sessionId: string) {&lt;br&gt;
  return await db.sessions.findUnique({ where: { id: sessionId } });&lt;br&gt;
}&lt;br&gt;
Database Schema (Drizzle ORM):&lt;/p&gt;

&lt;p&gt;// drizzle/schema.ts&lt;br&gt;
import { pgTable, text, timestamp, integer } from 'drizzle-orm/pg-core';&lt;/p&gt;

&lt;p&gt;export const sessions = pgTable('sessions', {&lt;br&gt;
  id: text('id').primaryKey(),&lt;br&gt;
  userId: integer('user_id').notNull().references(() =&amp;gt; users.id),&lt;br&gt;
  accessToken: text('access_token').notNull(),&lt;br&gt;
  refreshToken: text('refresh_token').notNull(),&lt;br&gt;
  expiresAt: timestamp('expires_at').notNull(),&lt;br&gt;
  createdAt: timestamp('created_at').notNull().defaultNow()&lt;br&gt;
});&lt;br&gt;
Pro Tip: Use Redis for sessions if you need sub-millisecond latency. Use PostgreSQL if you need ACID guarantees.&lt;/p&gt;

&lt;p&gt;📊 Impact: From Broken Auth to 99.9% Uptime&lt;br&gt;
After fixing these 5 issues in LariVid:&lt;/p&gt;

&lt;p&gt;Metric  Before  After&lt;br&gt;
Auth Success Rate   87% 99.2%&lt;br&gt;
Token Refresh Failures  15/day  0.3/day&lt;br&gt;
User Complaints 12/week 0/week&lt;br&gt;
Session Persistence 3 days avg  30 days avg&lt;br&gt;
CORS Errors 50/day  0/day&lt;br&gt;
Key Takeaway: OAuth is not "set it and forget it." You need monitoring, logging, and proactive token refresh.&lt;/p&gt;

&lt;p&gt;🛠️ Further Resources&lt;br&gt;
Manus OAuth Documentation&lt;br&gt;
OAuth 2.0 RFC 6749&lt;br&gt;
OpenID Connect Core 1.0&lt;br&gt;
OWASP OAuth Security Cheat Sheet&lt;br&gt;
💬 Have Similar Problems?&lt;br&gt;
If you're building on Manus and hitting OAuth issues, I'm happy to help. Reach out on Twitter @asxim19 or check out LariVid to see OAuth done right.&lt;/p&gt;

&lt;p&gt;Tags: #oauth #authentication #manus #web-development #debugging&lt;/p&gt;

&lt;p&gt;Published: January 18, 2026 | Author: ASXIM19, Founder &amp;amp; Developer @ LariVid&lt;/p&gt;

&lt;p&gt;&lt;a href="https://larivid.com/blog/manus-oauth-common-issues-solutions" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share:&lt;br&gt;
Twitter&lt;br&gt;
LinkedIn&lt;br&gt;
Reddit&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>authentication</category>
      <category>manus</category>
      <category>development</category>
    </item>
    <item>
      <title>How ONE Line of Code Blocked 12,508 Users</title>
      <dc:creator>Sinan Akkaya</dc:creator>
      <pubDate>Thu, 22 Jan 2026 05:57:00 +0000</pubDate>
      <link>https://dev.to/sinan_akkaya_192466cd17ad/how-one-line-of-code-blocked-12508-users-3566</link>
      <guid>https://dev.to/sinan_akkaya_192466cd17ad/how-one-line-of-code-blocked-12508-users-3566</guid>
      <description>&lt;p&gt;After 6 hours of debugging hell, I discovered ONE line of code&lt;br&gt;
was blocking all logins. A deep dive into cookie domain properties, CORB errors, and why modern web authentication is surprisingly fragile.  &lt;a href="https://larivid.com/blog/login-nightmare-cookie-domain" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>debugging</category>
      <category>cookies</category>
      <category>authentication</category>
    </item>
  </channel>
</rss>
