MeWrite Docs

Session Expired / Invalid Session

セッションの期限切れや無効化により認証状態が失われるエラー

概要

Session Expired / Invalid Session は、ユーザーのセッションがタイムアウトや無効化により失われた際に発生するエラーです。ログイン状態の維持ができなくなり、再認証が必要になります。

エラーメッセージ

Your session has expired. Please log in again.
Error: Session not found or expired
HTTP/1.1 401 Unauthorized
{"error": "invalid_session", "message": "Session has expired or is invalid"}
express-session: Session ID is invalid or expired

原因

  1. セッションタイムアウト: 一定時間操作がなくセッションが期限切れになった
  2. Cookie の消失: ブラウザの設定やSameSite属性によりCookieが送信されない
  3. サーバー再起動: インメモリセッションストアを使用している場合、再起動で消失
  4. ロードバランサーの設定: スティッキーセッションが設定されていない
  5. セッションストアの障害: Redis/Memcached 等のセッションストアがダウン

解決策

1. Express.js でのセッション設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');

const redisClient = createClient({ url: 'redis://localhost:6379' });
redisClient.connect();

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === 'production', // HTTPS 必須
    httpOnly: true,
    maxAge: 24 * 60 * 60 * 1000, // 24時間
    sameSite: 'lax' // CSRF対策
  }
}));

2. Django でのセッション設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# settings.py

# Redis をセッションバックエンドに使用
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}

# セッション有効期限(秒)
SESSION_COOKIE_AGE = 86400  # 24時間

# ブラウザを閉じてもセッション維持
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

# セッションCookieの設定
SESSION_COOKIE_SECURE = True      # HTTPS のみ
SESSION_COOKIE_HTTPONLY = True     # JavaScript からアクセス不可
SESSION_COOKIE_SAMESITE = 'Lax'   # CSRF対策

3. Laravel でのセッション設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// config/session.php
return [
    'driver' => env('SESSION_DRIVER', 'redis'),
    'lifetime' => 120,           // 分
    'expire_on_close' => false,
    'encrypt' => true,
    'cookie' => env('SESSION_COOKIE', 'app_session'),
    'secure' => env('SESSION_SECURE_COOKIE', true),
    'same_site' => 'lax',
    'http_only' => true,
];
1
2
3
4
5
6
7
8
// クロスサイトでCookieが送信されない場合
// SameSite=None; Secure が必要
app.use(session({
  cookie: {
    sameSite: 'none',  // クロスサイトで送信許可
    secure: true       // SameSite=None には Secure が必須
  }
}));

5. セッション延長(スライディングウィンドウ)

1
2
3
4
5
6
7
// Express.js: リクエストごとにセッション有効期限を延長
app.use((req, res, next) => {
  if (req.session) {
    req.session.touch(); // セッションの有効期限をリセット
  }
  next();
});
1
2
3
# Django: リクエストごとにセッションを更新
# settings.py
SESSION_SAVE_EVERY_REQUEST = True

6. フロントエンドでのセッション切れ対応

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// セッション切れを検知して再ログインに誘導
async function apiRequest(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    credentials: 'include' // Cookie を送信
  });

  if (response.status === 401) {
    const data = await response.json();
    if (data.error === 'invalid_session') {
      // セッション切れ通知を表示
      alert('セッションが切れました。再ログインしてください。');
      window.location.href = '/login?redirect=' + encodeURIComponent(window.location.pathname);
      return;
    }
  }

  return response;
}

関連エラー

Security の他のエラー

最終更新: 2026-02-03