Login API 在使用者登入失敗時,應該要回 200 , 401 還是 403 ?

Posted on

前陣子公司的一個新專案在實作登入功能,我們團隊便對 API 應該怎麼回傳錯誤這件事有了一些討論。想說這個討論還是挺不錯的,便想簡單記錄一下。

首先,標題提到了401 和 403,我們可以先來看一下這兩個 HTTP status code 分別代表什麼意思。

401 是 unauthorized,意思是「 使用者的 auth 資訊是錯的」,所以使用者只要調整成對的(登入或修正 access token 之類的),就要能存取該 API。

而 403 則是 forbidden,指的是「無論使用者怎麼調整,他都無權存取」。

這兩個錯誤常常在存取平常的資源時(像是 /articles 或 /friends),使用者沒有權限時 server 端可以分別按情況回傳給使用者的錯誤。

雖然有些人喜歡無論失敗或成功都直接在 response.body 中回應失敗與否,像這樣:

成功時

{
  ok: true,
  data: { /* resource */ }
}

失敗時

{
  ok: false,
  errorCode: "ERR_NO_PERMISSION"
}

但我自己不太贊同這種做法,陳皓的 這篇文章 也有提到,這種永遠回 200 的做法會造成監控系統的負擔。所以我個人並不推薦。

相對地,我會希望 Server 回給我符合語意的 HTTP Status Code,2XX 正常、3XX 重新導向、4XX 使用者端錯誤、5XX Server 端錯誤等等。

嗯,有點扯遠了。

回到本篇文章想討論的:「/login api 在使用者登入失敗時,究竟該回 200 、 401 還是 403 ?」

網路上簡單地爬了一下,看起來是沒有最佳實作。

我自己思考後的觀點是,因為這個 API 的用途就是「讓客戶端可以進行權限驗證」,所以這就是這個 API 的任務,無論結果是成功或失敗這個 API 都算是正常運作。所以我會認為應該回傳 200。至於是否在 response.body 中告知前端是哪個部分錯誤則是資安考量,此處先不討論。

或許也可以從另一個角度來看:如果一個系統有兩層登入——我知道這違反使用者體驗,但這邊僅作舉例、方便討論——這個時候使用者未登入第一層就嘗試要登入第二層時,第二層的登入 API 就可以回傳 401,告訴他沒有登入第一層就不能存取第二層 API。

NextAuth.js 的 API 設計看起來也是 支持我這個想法

Ref