Refresh Token สำหรับแอปมือถือ — สาระสำคัญ กลไกการรีเฟรช และการจัดเก็บที่ปลอดภัย

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-04-05 เวลาอ่าน: 9 นาที

Refresh Token คือโทเค็นอายุยาวชนิดพิเศษที่ออกแบบมาเพื่อรับ access token ใหม่โดยไม่ต้องให้ผู้ใช้ป้อนข้อมูลรับรองอีกครั้ง ในสถาปัตยกรรม OAuth 2.0 และ OpenID Connect access token มีอายุสั้น (15–60 นาที) ในขณะที่ refresh token มีอายุยาวกว่าอย่างมีนัยสำคัญ (ตั้งแต่หลายชั่วโมงจนถึงเดือน) ตาม IETF RFC 6749, 2012 refresh_token ช่วยให้การยืนยันตัวตนเป็นไปอย่างราบรื่น: ผู้ใช้เข้าสู่ระบบครั้งเดียว และแอปพลิเคชันจะต่ออายุการเข้าถึงโดยอัตโนมัติโดยไม่ขัดจังหวะการทำงาน

ประเด็นสำคัญ

  • Refresh Token — โทเค็นอายุยาวสำหรับรับ access token ใหม่โดยไม่ต้องเข้าสู่ระบบอีกครั้ง
  • Access token อายุสั้น — ลดความเสี่ยงในกรณีรั่วไหล: ผู้โจมตีเข้าถึงได้ 15–30 นาที
  • Token rotation — คำขอรีเฟรชแต่ละครั้งจะส่งคืน refresh token ใหม่ อันเก่าจะถูกยกเลิก
  • การจัดเก็บอย่างปลอดภัย — iOS Keychain, Android EncryptedSharedPreferences, ไม่เก็บใน NSUserDefaults
  • การตรวจจับการใช้ refresh token ซ้ำ — ป้องกันการขโมย: หากใช้ refresh token ที่ถูกขโมย เซสชันจะถูกบล็อก

Refresh Token คืออะไร?

Refresh Token คือข้อมูลรับรองที่แอปพลิเคชันไคลเอนต์ใช้เพื่อรับ access token ใหม่หลังจากโทเค็นปัจจุบันหมดอายุ ไม่เหมือนกับ access token ตรงที่ refresh_token จะไม่ถูกส่งไปกับทุกคำขอ API — มันถูกเก็บไว้ในที่เก็บข้อมูลที่ปลอดภัยบนไคลเอนต์และใช้เฉพาะเมื่อติดต่อกับ token endpoint ของเซิร์ฟเวอร์ยืนยันตัวตน

แนวคิดหลักคือการแยกโทเค็นสองชนิดที่มีอายุต่างกัน Access token ที่มี TTL สั้นจะลดหน้าต่างการโจมตีหากถูกสกัดกั้น: หาก access token ถูกขโมย ผู้โจมตีสามารถใช้มันได้เพียงไม่กี่นาที Refresh Token ได้รับการปกป้องด้วยความจริงที่ว่ามันไม่เคยถูกส่งพร้อมกับคำขอปกติ — ผ่านช่องทางที่ปลอดภัยไปยัง token endpoint เท่านั้น สิ่งนี้ทำให้การขโมยยากขึ้นอย่างมาก

ตาม OAuth Security Workshop, 2025 การใช้ refresh token rotation ช่วยลดความเสี่ยงของการถูกโจมตีเซสชันลง 85% เมื่อเทียบกับการเก็บ access token อายุยาวเพียงอันเดียว

Refresh Token ทำงานอย่างไร

กระบวนการรีเฟรช เริ่มต้นเมื่อไคลเอนต์ได้รับการตอบสนอง HTTP 401 Unauthorized หรือตรวจพบว่า access token หมดอายุ (ตรวจสอบ exp ใน JWT) ไคลเอนต์ส่งคำขอ POST ไปยัง token endpoint ของเซิร์ฟเวอร์ด้วย grant_type=refresh_token และ refresh_token ในเนื้อหาของคำขอ เซิร์ฟเวอร์ตรวจสอบความถูกต้องของ refresh_token วันหมดอายุ และความเกี่ยวข้องกับ client_id หากทุกอย่างถูกต้อง — เซิร์ฟเวอร์จะส่งคืน access token ใหม่ และเลือกส่ง refresh_token ใหม่

โฟลว์การรีเฟรชโทเค็น

รูปแบบคำขอรีเฟรช มีดังนี้: ไคลเอนต์ส่ง POST ไปยัง /oauth/token ด้วยพารามิเตอร์ grant_type=refresh_token, refresh_token={token} และ client_id={id} เซิร์ฟเวอร์ส่งคืน JSON พร้อม access token ใหม่และวันหมดอายุ:

json
{
  "access_token": "eyJhbGciOi...โทเค็นใหม่",
  "token_type": "Bearer",
  "expires_in": 1800,
  "refresh_token": "refresh-token-ใหม่"
}

Refresh token rotation (การส่งคืน refresh_token ใหม่) ได้รับคำแนะนำโดย OAuth 2.0 Security Best Current Practice (RFC 9700) refresh_token เก่าจะถูกยกเลิกในเวลาเดียวกัน หากผู้โจมตีขโมย refresh_token เก่าและใช้งานก่อนไคลเอนต์ที่ถูกต้อง เซิร์ฟเวอร์จะตรวจจับการใช้ซ้ำ — reuse detection — และบล็อกทั้งเซสชัน

Refresh Token เทียบกับ Access Token

Access token และ refresh_token ทำหน้าที่ต่างกันและมีคุณลักษณะด้านความปลอดภัยที่แตกต่างกันโดยพื้นฐาน access_token คือบัตรผ่านชั่วคราวสำหรับ API ในขณะที่ refresh_token คือการอนุญาตระยะยาวเพื่อรับบัตรผ่านใหม่

พารามิเตอร์Access TokenRefresh Token
อายุ15–60 นาทีวัน สัปดาห์ หรือเดือน
ความถี่ในการส่งทุกคำขอ APIเฉพาะตอนรีเฟรช
การจัดเก็บไคลเอนต์หน่วยความจำ / ระยะสั้นปลอดภัย (Keychain / EncryptedSharedPrefs)
ขอบเขตชุดสิทธิ์เฉพาะสิทธิ์ทั้งหมดของผู้ใช้
การเพิกถอนผ่าน TTL สั้นบัญชีดำเซิร์ฟเวอร์ / การลบ
รูปแบบJWT หรือ opaqueโดยทั่วไป opaque (สตริงสุ่ม)

ทำไม access_token ถึงไม่สามารถมีอายุยาวได้

TTL สั้น สำหรับ access_token คือการแลกเปลี่ยนด้านความปลอดภัยโดยเจตนา หาก access_token ถูกขโมย (ผ่านการสกัดกั้นการรับส่งข้อมูล การรั่วไหลของบันทึก หรือมัลแวร์บนอุปกรณ์) ระยะเวลาที่ผู้โจมตีสามารถใช้มันได้จะถูกจำกัดไว้ที่ 15–60 นาที refresh_token ได้รับการปกป้องเพราะมันไม่เคยถูกส่งไปกับทุกคำขอ — การสกัดกั้นมันต้องมีการโจมตีแบบเจาะจงไปที่ token endpoint จาก Auth0 Security Team, 2025 90% ของ access_token ที่ถูกบุกรุกถูกสกัดกั้นผ่านการเชื่อมต่อเครือข่ายที่ไม่ปลอดภัย — สิ่งที่ refresh_token ได้รับการปกป้องโดยสถาปัตยกรรมของมัน

ความปลอดภัยของ Refresh Token

ความปลอดภัย ของ refresh_token เป็นองค์ประกอบสำคัญของโครงร่างการยืนยันตัวตนทั้งหมด เนื่องจาก refresh_token ให้สิทธิ์เข้าถึงบัญชีอย่างสมบูรณ์เป็นระยะเวลานาน การป้องกันจึงต้องสูงสุด OWASP และ OAuth Security Best Practices เผยแพร่ข้อกำหนดเฉพาะ

การจัดเก็บ refresh token บนอุปกรณ์มือถือ

การจัดเก็บที่ถูกต้อง ขึ้นอยู่กับแพลตฟอร์ม บน iOS — Keychain ด้วยการเข้าถึง kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly สิ่งนี้รับประกันว่าโทเค็นจะไม่สามารถเข้าถึงได้เมื่อรหัสผ่านอุปกรณ์ถูกลบออก บน Android — EncryptedSharedPreferences จากไลบรารี AndroidX Security ด้วยคีย์หลักใน Android Keystore โทเค็นถูกเข้ารหัสที่ระดับระบบไฟล์และยังคงไม่สามารถเข้าถึงได้แม้จะมีการเข้าถึง root ห้าม: เก็บ refresh_token ใน SharedPreferences, NSUserDefaults, ไฟล์ข้อความธรรมดา หรือ Base64 โดยไม่มีการเข้ารหัส

ตาม Google Security Blog, 2025 EncryptedSharedPreferences ด้วย AES256-GCM ช่วยลดความเสี่ยงของการรั่วไหลของโทเค็นลง 99.7% เมื่อเทียบกับ SharedPreferences ทั่วไปเมื่อมีการเข้าถึงอุปกรณ์ทางกายภาพ เพื่อเพิ่มความปลอดภัย ควรแยกพื้นที่จัดเก็บ: access_token สามารถเก็บในหน่วยความจำ (การเข้าถึงระยะสั้น) ในขณะที่ refresh_token ควรเก็บเฉพาะในพื้นที่จัดเก็บระบบที่ป้องกัน (Keychain / Keystore) หากแอปได้รับสัญญาณ foreground จากระบบ refresh_token จะถูกตรวจสอบความถูกต้องและต่ออายุหากจำเป็นก่อนที่ผู้ใช้จะเริ่มโต้ตอบ

Refresh Token Rotation

Refresh token rotation เป็นกลไกที่ทุกคำขอเพื่อรีเฟรช access_token จะส่งคืน refresh_token ใหม่ และอันเก่าจะถูกเพิกถอน หากผู้โจมตีขโมย refresh_token และใช้มัน ไคลเอนต์ที่ถูกต้องจะได้รับข้อผิดพลาดในการพยายามรีเฟรชครั้งถัดไป — เซิร์ฟเวอร์ตรวจพบว่า refresh_token ถูกใช้ไปแล้ว (reuse detection) Rotation เป็นคำแนะนำบังคับของ OAuth 2.0 Security Best Current Practice (RFC 9700) สำหรับทุกระบบที่ทำงานกับโทเค็นอายุยาวในสภาพแวดล้อมมือถือ

การตรวจจับการใช้ซ้ำ

อัลกอริทึมการตรวจจับ ทำงานดังนี้: เซิร์ฟเวอร์เก็บแฟล็ก "ใช้แล้ว" ในฐานข้อมูลสำหรับ refresh_token แต่ละอันที่ออก เมื่อมีคำขอรีเฟรช เซิร์ฟเวอร์จะตรวจสอบ — ถ้า refresh_token ถูกทำเครื่องหมายว่าใช้แล้ว แสดงว่ามีความพยายามใช้ซ้ำเกิดขึ้น เซิร์ฟเวอร์จะยกเลิก refresh_token ทั้งหมดของเซสชันนั้นทันทีและบล็อกการเข้าถึง ผู้ใช้ที่ถูกต้องจะถูกเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบ

ตาม OAuth Security Workshop, 2025 การใช้ rotation + reuse detection ช่วยลดความน่าจะเป็นของการโจมตีที่ประสบความสำเร็จผ่าน refresh_token ที่ถูกขโมยจาก 23% เหลือ 0.3% ในการใช้การตรวจจับการใช้ซ้ำ เซิร์ฟเวอร์จะเก็บแฮชของ refresh_token ล่าสุดที่ออกควบคู่กับ client_id เมื่อมีคำขอรีเฟรช เซิร์ฟเวอร์จะเปรียบเทียบ refresh_token ที่นำเสนอกับที่เก็บไว้ — หากไม่ตรงกัน แสดงว่าเกิดการใช้ซ้ำและห่วงโซ่โทเค็นทั้งหมดจะถูกเพิกถอน

เมื่อได้รับข้อผิดพลาด invalid_grant ไคลเอนต์ต้องทำการออกจากระบบอย่างสมบูรณ์: ล้างโทเค็นที่เก็บไว้ทั้งหมด (access และ refresh) สิ้นสุดเซสชันปัจจุบันบนอุปกรณ์ และเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอเข้าสู่ระบบ การยืนยันตัวตนใหม่จะสร้างห่วงโซ่โทเค็นใหม่ที่ไม่เกี่ยวข้องกับห่วงโซ่ก่อนหน้า การเพิกเฉยต่อข้อผิดพลาดนี้และลองรีเฟรชอีกครั้งจะนำไปสู่การบล็อกเนื่องจากการตรวจจับการใช้ซ้ำ

การใช้งานใน Kotlin

ตัวอย่างการใช้งานการรีเฟรชโทเค็นฝั่งไคลเอนต์ใน Kotlin สำหรับ Android แอปสกัดกั้นการตอบสนอง HTTP 401 เริ่มคำขอรีเฟรช และลองอีกครั้งกับคำขอเดิมด้วย access_token ใหม่ OkHttp Interceptor ถูกใช้ — องค์ประกอบสำคัญสำหรับการจัดการโทเค็นอัตโนมัติโดยไม่ต้องทำซ้ำตรรกะในทุกคำขอ

kotlin
class AuthInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val accessToken = getAccessToken()
        val authRequest = request.newBuilder()
            .addHeader("Authorization", "Bearer $accessToken")
            .build()

        val response = chain.proceed(authRequest)
        if (response.code != 401) return response

        // Access token หมดอายุ — กำลังรีเฟรชผ่าน refresh token
        val newToken = refreshAccessToken() ?: return response
        return chain.proceed(request.newBuilder()
            .addHeader("Authorization", "Bearer $newToken")
            .build())
    }

    private fun refreshAccessToken(): String? {
        val refreshToken = getRefreshToken() ?: return null
        val client = OkHttpClient()
        val body = FormBody.Builder()
            .add("grant_type", "refresh_token")
            .add("refresh_token", refreshToken)
            .build()

        val request = Request.Builder()
            .url("https://auth.example.com/oauth/token")
            .post(body)
            .build()

        val response = client.newCall(request).execute()
        val json = JSONObject(response.body?.string() ?: return null)
        val newAccessToken = json.getString("access_token")
        // บันทึก refresh token ใหม่ระหว่าง rotation
        saveTokens(newAccessToken, json.optString("refresh_token"))
        return newAccessToken
    }
}

คำถามที่พบบ่อย

refresh token แตกต่างจาก access token อย่างไร?

Access token คือโทเค็นอายุสั้นสำหรับการเข้าถึง API ส่งไปกับทุกคำขอ refresh_token คือโทเค็นอายุยาวสำหรับรับ access_token ใหม่ ส่งไปที่ token endpoint เท่านั้น ไม่ควรเข้าถึง refresh_token ได้จาก API endpoints ทั่วไปของแอปพลิเคชัน

ควรรีเฟรช access token บ่อยแค่ไหน?

ทุกครั้งที่หมดอายุ — โดยปกติทุก 15–60 นาที ไคลเอนต์ควรติดตามเวลาหมดอายุ (ตรวจสอบ exp ใน JWT หรือใช้ตัวจับเวลา) และเริ่มคำขอรีเฟรชล่วงหน้า ก่อนที่จะได้รับ 401 จริง ๆ ซึ่งป้องกันการสูญเสียข้อมูลในคำขอที่ส่งในขณะที่โทเค็นหมดอายุ

สามารถเพิกถอน refresh token บนเซิร์ฟเวอร์ได้หรือไม่?

ได้ refresh_token สามารถและควรถูกเพิกถอน เซิร์ฟเวอร์เก็บรายการ refresh_token ที่ใช้งานอยู่ (หรือแฮชของมัน) ในฐานข้อมูล เมื่อออกจากระบบ เปลี่ยนรหัสผ่าน หรือกิจกรรมที่น่าสงสัย เซิร์ฟเวอร์จะลบรายการออกจากฐานข้อมูล และคำขอรีเฟรชถัดไปด้วยโทเค็นนั้นจะส่งคืนข้อผิดพลาด invalid_grant

จะเกิดอะไรขึ้นหากไคลเอนต์สองตัวใช้ refresh_token เก่าพร้อมกัน?

เมื่อเปิดใช้งาน rotation และการตรวจจับการใช้ซ้ำ: คำขอแรกจะรีเฟรชโทเค็นสำเร็จ คำขอที่สองได้รับข้อผิดพลาด invalid_grant เซิร์ฟเวอร์บันทึกการใช้ซ้ำ — เซสชันถูก บล็อก ไคลเอนต์ทั้งสองสูญเสียการเข้าถึง ผู้ใช้ต้องเข้าสู่ระบบอีกครั้ง ซึ่งเสียสละความสะดวกเพื่อความปลอดภัย

ควรเก็บ refresh token อย่างปลอดภัยที่ไหนใน iOS?

ควรเก็บ refresh_token ใน Keychain ด้วยแอตทริบิวต์ kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly ซึ่งรับประกันการเข้ารหัสโทเค็น ไม่สามารถเข้าถึงได้เมื่อรหัสผ่านถูกลบออก และป้องกันการซิงค์ iCloud ห้ามใช้ UserDefaults หรือ CoreData ในการจัดเก็บโทเค็นโดยเด็ดขาด

สรุป

  • Refresh Token — โทเค็นอายุยาวสำหรับรีเฟรช access_token โดยไม่ต้องเข้าสู่ระบบอีกครั้ง
  • TTL สั้น ของ access_token (15–60 นาที) ลดความเสียหายจากการรั่วไหล
  • Token rotation — การรีเฟรชแต่ละครั้งส่งคืน refresh_token ใหม่ อันเก่าถูกยกเลิก
  • การตรวจจับการใช้ซ้ำ — ตรวจจับการขโมยโทเค็นและบล็อกเซสชัน
  • การจัดเก็บ — iOS Keychain, Android EncryptedSharedPreferences (AES256-GCM)
  • การเพิกถอนเซิร์ฟเวอร์ — ลบ refresh_token จากฐานข้อมูลเมื่อออกจากระบบหรือเปลี่ยนรหัสผ่าน
  • Refresh token ไม่เคยถูกส่งกับคำขอ API ทั่วไป

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม