diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts
index 68bc01d936..ec5e524c67 100644
--- a/packages/constants/src/index.ts
+++ b/packages/constants/src/index.ts
@@ -2,3 +2,6 @@ export * from './regex'
 
 /** API 호출 시 필요한 사용자 세션 HTTP 헤더 키  */
 export const SESSION_KEY = 'x-soto-session'
+export const TP_TK = 'TP_TK'
+export const TP_SE = 'TP_SE'
+export const X_TRIPLE_WEB_DEVICE_ID = 'x-triple-web-device-id'
diff --git a/packages/public-header/src/side-menu/profile.tsx b/packages/public-header/src/side-menu/profile.tsx
index 783882421e..fa3f1a7690 100644
--- a/packages/public-header/src/side-menu/profile.tsx
+++ b/packages/public-header/src/side-menu/profile.tsx
@@ -73,6 +73,8 @@ const PROFILE_EVENT_METADATA_LABEL = {
   photo: '프로필사진',
 }
 
+const NOL_CONNECTED_LABEL = 'NOL 멤버스 계정'
+
 export function Profile() {
   const user = useUser()
   const { trackEvent } = useEventTrackingContext()
@@ -80,6 +82,10 @@ export function Profile() {
   const returnUrl = encodeURIComponent(location.href)
   const providerIconSrc = user ? PROVIDER_INFO[user.provider].icon : undefined
   const badgeUrl = user ? user.mileage?.badges[0]?.icon.image_url : undefined
+  const providerVisible = user && !user.nolConnected
+  const profileLabel = providerVisible
+    ? user.email || PROVIDER_INFO[user.provider].label
+    : NOL_CONNECTED_LABEL
 
   const onProfileClick = (
     referrer: keyof typeof PROFILE_EVENT_METADATA_LABEL,
@@ -105,10 +111,10 @@ export function Profile() {
       <Container>
         <UserName onClick={() => onProfileClick('name')}>{user.name}</UserName>
         <UserEmailOrProvider>
-          {providerIconSrc ? (
+          {providerIconSrc && providerVisible ? (
             <SocialIcon src={providerIconSrc} alt="social login icon" />
           ) : null}
-          {user.email || PROVIDER_INFO[user.provider].label}
+          {profileLabel}
         </UserEmailOrProvider>
       </Container>
 
diff --git a/packages/react-contexts/package.json b/packages/react-contexts/package.json
index a33e5306e0..712f686d3e 100644
--- a/packages/react-contexts/package.json
+++ b/packages/react-contexts/package.json
@@ -72,7 +72,8 @@
     "semver": "^7.5.4",
     "set-cookie-parser": "^2.7.1",
     "ua-parser-js": "^1.0.37",
-    "universal-cookie": "^4.0.4"
+    "universal-cookie": "^4.0.4",
+    "uuid": "^11.1.0"
   },
   "devDependencies": {
     "@types/qs": "^6.9.9",
diff --git a/packages/react-contexts/src/middlewares/chain.ts b/packages/react-contexts/src/middlewares/chain.ts
index 80c03ff054..9f89425d92 100644
--- a/packages/react-contexts/src/middlewares/chain.ts
+++ b/packages/react-contexts/src/middlewares/chain.ts
@@ -1,16 +1,11 @@
-import { NextResponse } from 'next/server'
-import type { NextFetchEvent, NextRequest } from 'next/server'
+import { NextMiddleware, NextResponse } from 'next/server'
 
-import { CustomMiddleware, MiddlewareFactory } from './types'
+import { MiddlewareFactory } from './types'
 
-/**
- * TF 14.0.11의 middlewares/src/chain 참고하여 작성
- * https://github.com/titicacadev/triple-frontend/blob/ceee9a7116dfbf39cc1363013a43cfb0060a9539/packages/middlewares/src/chain.ts
- */
 export function chain(
   functions: MiddlewareFactory[],
   index = 0,
-): CustomMiddleware {
+): NextMiddleware {
   const current = functions[index]
 
   if (current) {
@@ -18,11 +13,7 @@ export function chain(
     return current(next)
   }
 
-  return (
-    request: NextRequest,
-    event: NextFetchEvent,
-    response: NextResponse,
-  ) => {
-    return response
+  return () => {
+    return NextResponse.next()
   }
 }
diff --git a/packages/react-contexts/src/middlewares/constants.ts b/packages/react-contexts/src/middlewares/constants.ts
deleted file mode 100644
index 1203e84c5a..0000000000
--- a/packages/react-contexts/src/middlewares/constants.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export const TP_TK = 'TP_TK'
-export const TP_SE = 'TP_SE'
diff --git a/packages/react-contexts/src/middlewares/index.ts b/packages/react-contexts/src/middlewares/index.ts
index bb364a75e9..6ff8e38c41 100644
--- a/packages/react-contexts/src/middlewares/index.ts
+++ b/packages/react-contexts/src/middlewares/index.ts
@@ -1,10 +1,9 @@
 import { chain } from './chain'
 import type { MiddlewareFactory } from './types'
 import { refreshSessionMiddleware } from './refresh-session'
-
-export { oldTripleIosCookiesMiddleware } from './old-triple-ios-cookie'
+import { setWebDeviceIdMiddleware } from './set-web-device-id'
 
 export const constructMiddleware = (functions: MiddlewareFactory[]) =>
-  chain([...functions, refreshSessionMiddleware])
+  chain([...functions, refreshSessionMiddleware, setWebDeviceIdMiddleware])
 
 export * from './types'
diff --git a/packages/react-contexts/src/middlewares/old-triple-ios-cookie.ts b/packages/react-contexts/src/middlewares/old-triple-ios-cookie.ts
deleted file mode 100644
index ce7c7bbf92..0000000000
--- a/packages/react-contexts/src/middlewares/old-triple-ios-cookie.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { NextRequest, NextResponse, NextFetchEvent } from 'next/server'
-import satisfies from 'semver/functions/satisfies'
-
-import { parseApp } from '../user-agent-context'
-
-import { CustomMiddleware } from './types'
-
-/**
- * TF 13.42.1의 react-contexts/src/middleware 참고하여 작성
- * https://github.com/titicacadev/triple-frontend/blob/8d002e80f9ff187d6a06b6a2695c48f1d5383662/packages/react-contexts/src/middleware.ts
- */
-export function oldTripleIosCookiesMiddleware(
-  customMiddleware: CustomMiddleware,
-) {
-  return function middleware(request: NextRequest, event: NextFetchEvent) {
-    const response = NextResponse.next()
-
-    const userAgent = request.headers.get('User-Agent')
-
-    const host = request.headers.get('x-forwarded-host')
-
-    const tripleApp = userAgent ? parseApp(userAgent) : null
-
-    if (!userAgent || (host && !!tripleApp)) {
-      return customMiddleware(request, event, response)
-    }
-
-    try {
-      const oldVersionRange = '< 6.5.5'
-      const isOldIosApp =
-        tripleApp &&
-        tripleApp.name === 'Triple-iOS' &&
-        satisfies(tripleApp.version, oldVersionRange, {
-          includePrerelease: true,
-        })
-
-      if (isOldIosApp) {
-        const cookies = request.cookies.getAll()
-
-        cookies.forEach((cookie) => {
-          response.cookies.set(cookie.name, cookie.value)
-        })
-      }
-    } catch {
-      // semver 파싱 에러가 발생하면 ignore 합니다.
-    }
-
-    return customMiddleware(request, event, response)
-  }
-}
diff --git a/packages/react-contexts/src/middlewares/refresh-session.ts b/packages/react-contexts/src/middlewares/refresh-session.ts
index 6edc005750..2154c200ce 100644
--- a/packages/react-contexts/src/middlewares/refresh-session.ts
+++ b/packages/react-contexts/src/middlewares/refresh-session.ts
@@ -1,31 +1,51 @@
-import { NextFetchEvent, NextRequest, NextResponse } from 'next/server'
+import { type ResponseCookie } from 'next/dist/compiled/@edge-runtime/cookies'
+import {
+  NextFetchEvent,
+  NextMiddleware,
+  NextRequest,
+  NextResponse,
+} from 'next/server'
 import { get, post } from '@titicaca/fetcher'
 import { parseString, splitCookiesString } from 'set-cookie-parser'
+import {
+  TP_SE,
+  TP_TK,
+  SESSION_KEY as X_SOTO_SESSION,
+} from '@titicaca/constants'
 
-import { CustomMiddleware } from './types'
-import { TP_SE, TP_TK } from './constants'
+import { parseApp } from '../user-agent-context'
 
-export function refreshSessionMiddleware(customMiddleware: CustomMiddleware) {
+import { applySetCookie } from './utils/apply-set-cookie'
+
+export function refreshSessionMiddleware(next: NextMiddleware) {
   return async function middleware(
     request: NextRequest,
     event: NextFetchEvent,
   ) {
+    const response = (await next(request, event)) as NextResponse
     const url = request.nextUrl
 
     const isPageUrl = url.pathname.match('^/((?!(api|static|.*\\..*|_next)).*)')
     if (!isPageUrl) {
-      return customMiddleware(request, event, NextResponse.next())
+      return response
     }
 
     const allCookies = request.cookies.getAll()
 
-    const isSessionExisted = allCookies.some(
+    const userAgent = request.headers.get('User-Agent')
+    const tripleApp = userAgent ? parseApp(userAgent) : null
+
+    const cookiesWithoutXSotoSession = tripleApp
+      ? allCookies
+      : allCookies.filter(({ name }) => name !== X_SOTO_SESSION)
+
+    const isSessionExisted = cookiesWithoutXSotoSession.some(
       ({ name }) => name === TP_TK || name === TP_SE,
     )
-    const cookies = deriveAllCookies(request.cookies.getAll())
+    const cookies = deriveAllCookies(cookiesWithoutXSotoSession)
 
     if (!isSessionExisted) {
-      return customMiddleware(request, event, NextResponse.next())
+      return response
     }
 
     const options = {
@@ -36,7 +56,7 @@ export function refreshSessionMiddleware(customMiddleware: CustomMiddleware) {
     const firstTrialResponse = await get('/api/users/me', options)
 
     if (firstTrialResponse.status !== 401) {
-      return customMiddleware(request, event, NextResponse.next())
+      return response
     }
 
     /**
@@ -48,35 +68,21 @@ export function refreshSessionMiddleware(customMiddleware: CustomMiddleware) {
       const setCookie = refreshResponse.headers.get('set-cookie')
 
       if (setCookie) {
-        const oldCookies = splitCookiesString(
-          request.headers.get('cookie') || '',
-        )
+        const response = (await next(request, event)) as NextResponse
         const setCookies = splitCookiesString(setCookie)
-
-        const newCookies = oldCookies.reduce((map, cookie) => {
-          const { name } = parseString(cookie)
-          return map.set(name, cookie)
-        }, new Map())
-
         setCookies.forEach((cookie) => {
-          const { name } = parseString(cookie)
-          newCookies.set(name, cookie)
+          const { name, value, ...rest } = parseString(cookie)
+          if (name !== X_SOTO_SESSION) {
+            response.cookies.set(name, value, { ...(rest as ResponseCookie) })
+          }
         })
+        applySetCookie(request, response)
 
-        const finalCookie = [...newCookies.values()].join('; ')
-
-        request.headers.set('cookie', finalCookie)
-
-        const response = NextResponse.next({
-          request,
-        })
-
-        response.headers.set('set-cookie', setCookie)
-
-        return customMiddleware(request, event, response)
+        return response
       }
     }
-    return customMiddleware(request, event, NextResponse.next())
+
+    return response
   }
 }
 
diff --git a/packages/react-contexts/src/middlewares/set-web-device-id.ts b/packages/react-contexts/src/middlewares/set-web-device-id.ts
new file mode 100644
index 0000000000..7f61995c4e
--- /dev/null
+++ b/packages/react-contexts/src/middlewares/set-web-device-id.ts
@@ -0,0 +1,40 @@
+import {
+  NextFetchEvent,
+  NextMiddleware,
+  NextRequest,
+  NextResponse,
+} from 'next/server'
+import { v4 as uuidV4 } from 'uuid'
+import { X_TRIPLE_WEB_DEVICE_ID } from '@titicaca/constants'
+
+import { getTripleApp } from './utils/get-triple-app'
+import { applySetCookie } from './utils/apply-set-cookie'
+
+export function setWebDeviceIdMiddleware(next: NextMiddleware) {
+  return async function middleware(
+    request: NextRequest,
+    event: NextFetchEvent,
+  ) {
+    const response = (await next(request, event)) as NextResponse
+    const tripleApp = getTripleApp(request)
+
+    if (tripleApp) {
+      return response
+    }
+
+    const allCookies = request.cookies.getAll()
+    const hasWebDeviceId = allCookies.some(
+      ({ name }) => name === X_TRIPLE_WEB_DEVICE_ID,
+    )
+
+    if (!hasWebDeviceId && response?.cookies) {
+      const randomWebDeviceId = uuidV4()
+      response.cookies.set(X_TRIPLE_WEB_DEVICE_ID, randomWebDeviceId, {
+        secure: true,
+      })
+      applySetCookie(request, response)
+    }
+
+    return response
+  }
+}
diff --git a/packages/react-contexts/src/middlewares/types.ts b/packages/react-contexts/src/middlewares/types.ts
index 6638b6b286..1e3a7a7e85 100644
--- a/packages/react-contexts/src/middlewares/types.ts
+++ b/packages/react-contexts/src/middlewares/types.ts
@@ -1,12 +1,3 @@
-import { NextMiddlewareResult } from 'next/dist/server/web/types'
-import { NextFetchEvent, NextRequest, NextResponse } from 'next/server'
+import { NextMiddleware } from 'next/server'
 
-export type CustomMiddleware = (
-  request: NextRequest,
-  event: NextFetchEvent,
-  response: NextResponse,
-) => NextMiddlewareResult | Promise<NextMiddlewareResult>
-
-export type MiddlewareFactory = (
-  middleware: CustomMiddleware,
-) => CustomMiddleware
+export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware
diff --git a/packages/react-contexts/src/middlewares/utils/apply-set-cookie.ts b/packages/react-contexts/src/middlewares/utils/apply-set-cookie.ts
new file mode 100644
index 0000000000..2088ef2274
--- /dev/null
+++ b/packages/react-contexts/src/middlewares/utils/apply-set-cookie.ts
@@ -0,0 +1,27 @@
+import {
+  RequestCookies,
+  ResponseCookies,
+} from 'next/dist/compiled/@edge-runtime/cookies'
+import { NextRequest, NextResponse } from 'next/server'
+
+/** Reference: https://github.com/vercel/next.js/discussions/50374#discussioncomment-6732402
+ * response.cookies.set 사용 시 response의 set-cookie로 값이 적용되기 때문에 이를 response의 headers.cookie로 설정해주는 함수입니다.
+ *
+ */
+export function applySetCookie(req: NextRequest, res: NextResponse) {
+  const setCookies = new ResponseCookies(res.headers)
+  const newReqHeaders = new Headers(req.headers)
+  const newReqCookies = new RequestCookies(newReqHeaders)
+  setCookies.getAll().forEach((cookie) => newReqCookies.set(cookie))
+
+  const dummyRes = NextResponse.next({ request: { headers: newReqHeaders } })
+
+  dummyRes.headers.forEach((value, key) => {
+    if (
+      key === 'x-middleware-override-headers' ||
+      key.startsWith('x-middleware-request-')
+    ) {
+      res.headers.set(key, value)
+    }
+  })
+}
diff --git a/packages/react-contexts/src/middlewares/utils/get-triple-app.ts b/packages/react-contexts/src/middlewares/utils/get-triple-app.ts
new file mode 100644
index 0000000000..19e69efaab
--- /dev/null
+++ b/packages/react-contexts/src/middlewares/utils/get-triple-app.ts
@@ -0,0 +1,10 @@
+import { NextRequest } from 'next/server'
+
+import { parseApp } from '../../user-agent-context'
+
+export function getTripleApp(request: NextRequest) {
+  const userAgent = request.headers.get('User-Agent')
+  const tripleApp = userAgent ? parseApp(userAgent) : null
+
+  return tripleApp
+}
diff --git a/packages/react-contexts/src/session-context/browser.tsx b/packages/react-contexts/src/session-context/browser.tsx
index 921f321bcb..c9797ab9e7 100644
--- a/packages/react-contexts/src/session-context/browser.tsx
+++ b/packages/react-contexts/src/session-context/browser.tsx
@@ -13,6 +13,7 @@ import {
 import { generateUrl } from '@titicaca/view-utilities'
 import qs from 'qs'
 import Cookies from 'universal-cookie'
+import { TP_TK } from '@titicaca/constants'
 
 import { GET_USER_REQUEST_URL, User, UserProvider, useUserState } from './user'
 import {
@@ -132,9 +133,5 @@ InBrowserSessionContextProvider.getInitialProps = async function ({
 export function getWebSessionAvailabilityFromRequest(
   req: IncomingMessage | undefined,
 ) {
-  if (process.env.NODE_ENV !== 'production') {
-    return !!new Cookies(req?.headers.cookie).get('TP_SE')
-  }
-
-  return !!req?.headers['x-triple-web-login']
+  return !!new Cookies(req?.headers.cookie).get(TP_TK)
 }
diff --git a/packages/react-contexts/src/session-context/index.tsx b/packages/react-contexts/src/session-context/index.tsx
index e84d9e55a6..fc7bedef5a 100644
--- a/packages/react-contexts/src/session-context/index.tsx
+++ b/packages/react-contexts/src/session-context/index.tsx
@@ -1,5 +1,5 @@
 export { default as SessionContextProvider } from './provider'
 export { useSessionAvailability, useSessionControllers } from './hooks'
-export { useUser } from './user'
+export { useUser, User } from './user'
 export { default as getSessionAvailabilityFromRequest } from './session-availability'
 export { putInvalidSessionIdRemover } from './invalid-session-id-remover'
diff --git a/packages/react-contexts/src/session-context/session-availability.ts b/packages/react-contexts/src/session-context/session-availability.ts
index b15d6ed5a4..1f4b18f6b4 100644
--- a/packages/react-contexts/src/session-context/session-availability.ts
+++ b/packages/react-contexts/src/session-context/session-availability.ts
@@ -1,6 +1,6 @@
 import { IncomingMessage } from 'http'
 
-import { generateUserAgentValues } from '..'
+import { parseApp } from '..'
 
 import { getSessionIdFromRequest } from './app'
 import { getWebSessionAvailabilityFromRequest } from './browser'
@@ -8,9 +8,9 @@ import { getWebSessionAvailabilityFromRequest } from './browser'
 export default function getSessionAvailabilityFromRequest(
   req: IncomingMessage | undefined,
 ) {
-  const { isPublic } = generateUserAgentValues(req?.headers['user-agent'] || '')
+  const app = parseApp(req?.headers['user-agent'] || '')
 
-  if (isPublic === true) {
+  if (!app) {
     return getWebSessionAvailabilityFromRequest(req)
   }
 
diff --git a/packages/react-contexts/src/session-context/user.ts b/packages/react-contexts/src/session-context/user.ts
index d39c426710..c85743bd94 100644
--- a/packages/react-contexts/src/session-context/user.ts
+++ b/packages/react-contexts/src/session-context/user.ts
@@ -10,6 +10,8 @@ export interface User {
   mileage: Mileage
   uid: string
   email: string
+  nolConnected?: boolean
+  nolConnectedAt?: string
 }
 
 type Provider = 'TRIPLE' | 'NAVER' | 'KAKAO' | 'FACEBOOK' | 'APPLE'
diff --git a/packages/react-contexts/src/user-agent-context/utils.ts b/packages/react-contexts/src/user-agent-context/utils.ts
index 6c414667ee..e435ab14a4 100644
--- a/packages/react-contexts/src/user-agent-context/utils.ts
+++ b/packages/react-contexts/src/user-agent-context/utils.ts
@@ -5,7 +5,7 @@ enum AppName {
   Android = 'Triple-Android',
 }
 
-interface App {
+export interface App {
   name: AppName
   version: string
 }
diff --git a/packages/ui-flow/src/auth-guard/index.ts b/packages/ui-flow/src/auth-guard/index.ts
index f95fbf4a2f..26045f8aec 100644
--- a/packages/ui-flow/src/auth-guard/index.ts
+++ b/packages/ui-flow/src/auth-guard/index.ts
@@ -3,12 +3,10 @@ import { get } from '@titicaca/fetcher'
 import { parseTripleClientUserAgent } from '@titicaca/react-triple-client-interfaces'
 import qs from 'qs'
 import { generateUrl, parseUrl, strictQuery } from '@titicaca/view-utilities'
-import { getSessionAvailabilityFromRequest } from '@titicaca/react-contexts'
-
-interface UserResponse {
-  uid: string
-  // TODO
-}
+import {
+  getSessionAvailabilityFromRequest,
+  User,
+} from '@titicaca/react-contexts'
 
 interface AuthGuardOptions {
   authType?: string
@@ -25,7 +23,7 @@ const NON_MEMBER_REGEX = /^_PH/
 export function authGuard<Props>(
   gssp: (
     ctx: GetServerSidePropsContext & {
-      customContext?: { user?: UserResponse }
+      customContext?: { user?: User }
     },
   ) => Promise<GetServerSidePropsResult<Props>>,
   options?: AuthGuardOptions,
@@ -47,7 +45,7 @@ export function authGuard<Props>(
       ? options.resolveReturnUrl(ctx)
       : `${process.env.NEXT_PUBLIC_BASE_PATH || ''}${resolvedUrl}`
 
-    const response = await get<UserResponse>('/api/users/me', {
+    const response = await get<User>('/api/users/me', {
       req,
       retryable: true,
     })
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 69a1534440..d2d7434606 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1185,6 +1185,9 @@ importers:
       universal-cookie:
         specifier: ^4.0.4
         version: 4.0.4
+      uuid:
+        specifier: ^11.1.0
+        version: 11.1.0
     devDependencies:
       '@types/qs':
         specifier: ^6.9.9
@@ -11591,6 +11594,10 @@ packages:
     resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
     engines: {node: '>= 0.4.0'}
 
+  uuid@11.1.0:
+    resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
+    hasBin: true
+
   uuid@9.0.0:
     resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
     hasBin: true
@@ -24465,6 +24472,8 @@ snapshots:
 
   utils-merge@1.0.1: {}
 
+  uuid@11.1.0: {}
+
   uuid@9.0.0: {}
 
   uvu@0.5.6: