--- /dev/null
+# ν¨μ€μλμ Bearerλ₯Ό μ΄μ©ν κ°λ¨ν OAuth2
+
+μ΄μ μ΄μ μ₯μμ λΉλνκ³ λλ½λ λΆλΆμ μΆκ°νμ¬ μμ ν 보μ νλ¦μ κ°λλ‘ νκ² μ΅λλ€.
+
+## `username`μ `password` μ»κΈ°
+
+**FastAPI** 보μ μ νΈλ¦¬ν°λ₯Ό μ¬μ©νμ¬ `username` λ° `password`λ₯Ό κ°μ Έμ¬ κ²μ
λλ€.
+
+OAuth2λ (μ°λ¦¬κ° μ¬μ©νκ³ μλ) "ν¨μ€μλ νλ‘μ°"μ μ¬μ©ν λ ν΄λΌμ΄μΈνΈ/μ μ κ° `username` λ° `password` νλλ₯Ό νΌ λ°μ΄ν°λ‘ 보λ΄μΌ ν¨μ μ§μ ν©λλ€.
+
+κ·Έλ¦¬κ³ μ¬μμλ νλμ μ΄λ¦μ κ·Έλ κ² μ§μ ν΄μΌ νλ€κ³ λμ μμ΅λλ€. λ°λΌμ `user-name` λλ `email`μ μλνμ§ μμ΅λλ€.
+
+νμ§λ§ κ±±μ νμ§ μμλ λ©λλ€. νλ°νΈμλμμ μ΅μ’
μ¬μ©μμκ² μνλ λλ‘ νμν μ μμ΅λλ€.
+
+κ·Έλ¦¬κ³ λ°μ΄ν°λ² μ΄μ€ λͺ¨λΈμ μνλ λ€λ₯Έ μ΄λ¦μ μ¬μ©ν μ μμ΅λλ€.
+
+κ·Έλ¬λ λ‘κ·ΈμΈ *κ²½λ‘ μλ*μ κ²½μ° μ¬μκ³Ό νΈνλλλ‘ μ΄λ¬ν μ΄λ¦μ μ¬μ©ν΄μΌ ν©λλ€(μλ₯Ό λ€μ΄ ν΅ν© API λ¬Έμ μμ€ν
μ μ¬μ©ν μ μμ΄μΌ ν©λλ€).
+
+μ¬μμλ λν `username`κ³Ό `password`κ° νΌ λ°μ΄ν°λ‘ μ μ‘λμ΄μΌ νλ€κ³ λͺ
μλμ΄ μμ΅λλ€(λ°λΌμ μ¬κΈ°μλ JSONμ΄ μμ΅λλ€).
+
+### `scope`
+
+μ¬μμλ ν΄λΌμ΄μΈνΈκ° λ€λ₯Έ νΌ νλ "`scope`"λ₯Ό λ³΄λΌ μ μλ€κ³ λμ μμ΅λλ€.
+
+νΌ νλ μ΄λ¦μ `scope`(λ¨μν)μ΄μ§λ§ μ€μ λ‘λ 곡백μΌλ‘ ꡬλΆλ "λ²μ"κ° μλ κΈ΄ λ¬Έμμ΄μ
λλ€.
+
+κ° "λ²μ"λ κ³΅λ°±μ΄ μλ λ¬Έμμ΄μ
λλ€.
+
+μΌλ°μ μΌλ‘ νΉμ 보μ κΆνμ μ μΈνλ λ° μ¬μ©λ©λλ€. λ€μμ λ΄
μλ€:
+
+* `users:read` λλ `users:write`λ μΌλ°μ μΈ μμμ
λλ€.
+* `instagram_basic`μ νμ΄μ€λΆ/μΈμ€νκ·Έλ¨μμ μ¬μ©ν©λλ€.
+* `https://www.googleapis.com/auth/drive`λ Googleμμ μ¬μ©ν©λλ€.
+
+!!! μ 보
+ OAuth2μμ "λ²μ"λ νμν νΉμ κΆνμ μ μΈνλ λ¬Έμμ΄μ
λλ€.
+
+ `:`κ³Ό κ°μ λ€λ₯Έ λ¬Έμκ° μλμ§ λλ URLμΈμ§λ μ€μνμ§ μμ΅λλ€.
+
+ μ΄λ¬ν μΈλΆ μ¬νμ ꡬνμ λ°λΌ λ€λ¦
λλ€.
+
+ OAuth2μ κ²½μ° λ¬Έμμ΄μΌ λΏμ
λλ€.
+
+## `username`κ³Ό `password`λ₯Ό κ°μ Έμ€λ μ½λ
+
+μ΄μ **FastAPI**μμ μ 곡νλ μ νΈλ¦¬ν°λ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό μ²λ¦¬ν΄ λ³΄κ² μ΅λλ€.
+
+### `OAuth2PasswordRequestForm`
+
+λ¨Όμ `OAuth2PasswordRequestForm`μ κ°μ Έμ `/token`μ λν *κ²½λ‘ μλ*μμ `Depends`μ μμ‘΄μ±μΌλ‘ μ¬μ©ν©λλ€.
+
+=== "νμ΄μ¬ 3.7 μ΄μ"
+
+ ```Python hl_lines="4 76"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "νμ΄μ¬ 3.10 μ΄μ"
+
+ ```Python hl_lines="2 74"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+`OAuth2PasswordRequestForm`μ λ€μμ μ¬μ©νμ¬ νΌ λ³Έλ¬Έμ μ μΈνλ ν΄λμ€ μμ‘΄μ±μ
λλ€:
+
+* `username`.
+* `password`.
+* `scope`λ μ νμ μΈ νλλ‘ κ³΅λ°±μΌλ‘ ꡬλΆλ λ¬Έμμ΄λ‘ ꡬμ±λ ν° λ¬Έμμ΄μ
λλ€.
+* `grant_type`(μ νμ μΌλ‘ μ¬μ©).
+
+!!! ν
+ OAuth2 μ¬μμ μ€μ λ‘ `password`λΌλ κ³ μ κ°μ΄ μλ `grant_type` νλλ₯Ό *μꡬ*νμ§λ§ `OAuth2PasswordRequestForm`μ μ΄λ₯Ό κ°μνμ§ μμ΅λλ€.
+
+ μ¬μ©ν΄μΌ νλ€λ©΄ `OAuth2PasswordRequestForm` λμ `OAuth2PasswordRequestFormStrict`λ₯Ό μ¬μ©νλ©΄ λ©λλ€.
+
+* `client_id`(μ νμ μΌλ‘ μ¬μ©) (μμ μμλ νμνμ§ μμ΅λλ€).
+* `client_secret`(μ νμ μΌλ‘ μ¬μ©) (μμ μμλ νμνμ§ μμ΅λλ€).
+
+!!! μ 보
+ `OAuth2PasswordRequestForm`μ `OAuth2PasswordBearer`μ κ°μ΄ **FastAPI**μ λν νΉμ ν΄λμ€κ° μλλλ€.
+
+ `OAuth2PasswordBearer`λ **FastAPI**κ° λ³΄μ 체κ³μμ μλλ‘ ν©λλ€. κ·Έλμ OpenAPIμ κ·Έλ κ² μΆκ°λ©λλ€.
+
+ κ·Έλ¬λ `OAuth2PasswordRequestForm`μ μ§μ μμ±νκ±°λ `Form` λ§€κ°λ³μλ₯Ό μ§μ μ μΈν μ μλ ν΄λμ€ μμ‘΄μ±μΌ λΏμ
λλ€.
+
+ κ·Έλ¬λ μΌλ°μ μΈ μ¬μ© μ¬λ‘μ΄λ―λ‘ λ μ½κ² νκΈ° μν΄ **FastAPI**μμ μ§μ μ 곡ν©λλ€.
+
+### νΌ λ°μ΄ν° μ¬μ©νκΈ°
+
+!!! ν
+ μ’
μμ± ν΄λμ€ `OAuth2PasswordRequestForm`μ μΈμ€ν΄μ€μλ 곡백μΌλ‘ ꡬλΆλ κΈ΄ λ¬Έμμ΄μ΄ μλ `scope` μμ±μ΄ μκ³ λμ μ μ‘λ κ° λ²μμ λν μ€μ λ¬Έμμ΄ λͺ©λ‘μ΄ μλ `scopes` μμ±μ΄ μμ΅λλ€.
+
+ μ΄ μμ μμλ `scopes`λ₯Ό μ¬μ©νμ§ μμ§λ§ νμν κ²½μ°, κΈ°λ₯μ΄ μμ΅λλ€.
+
+μ΄μ νΌ νλμ `username`μ μ¬μ©νμ¬ (κ°μ§) λ°μ΄ν°λ² μ΄μ€μμ μ μ λ°μ΄ν°λ₯Ό κ°μ Έμ΅λλ€.
+
+ν΄λΉ μ¬μ©μκ° μμΌλ©΄ "μλͺ»λ μ¬μ©μ μ΄λ¦ λλ ν¨μ€μλ"λΌλ μ€λ₯κ° λ°νλ©λλ€.
+
+μ€λ₯μ κ²½μ° `HTTPException` μμΈλ₯Ό μ¬μ©ν©λλ€:
+
+=== "νμ΄μ¬ 3.7 μ΄μ"
+
+ ```Python hl_lines="3 77-79"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "νμ΄μ¬ 3.10 μ΄μ"
+
+ ```Python hl_lines="1 75-77"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+### ν¨μ€μλ νμΈνκΈ°
+
+μ΄ μμ μμ λ°μ΄ν°λ² μ΄μ€μ μ¬μ©μ λ°μ΄ν° νμμ νμΈνμ§λ§ μνΈλ₯Ό νμΈνμ§ μμμ΅λλ€.
+
+λ¨Όμ λ°μ΄ν°λ₯Ό Pydantic `UserInDB` λͺ¨λΈμ λ£κ² μ΅λλ€.
+
+μΌλ° ν
μ€νΈ μνΈλ₯Ό μ μ₯νλ©΄ μ λλ (κ°μ§) μνΈ ν΄μ± μμ€ν
μ μ¬μ©ν©λλ€.
+
+λ ν¨μ€μλκ° μΌμΉνμ§ μμΌλ©΄ λμΌν μ€λ₯κ° λ°νλ©λλ€.
+
+#### ν¨μ€μλ ν΄μ±
+
+"ν΄μ±"μ μΌλΆ μ½ν
μΈ (μ΄ κ²½μ° ν¨μ€μλ)λ₯Ό ν‘μ€μμ€νλ κ²μ²λΌ 보μ΄λ μΌλ ¨μ λ°μ΄νΈ(λ¬Έμμ΄)λ‘ λ³ννλ κ²μ μλ―Έν©λλ€.
+
+μ νν λμΌν μ½ν
μΈ (μ νν λμΌν ν¨μ€μλ)λ₯Ό μ λ¬ν λλ§λ€ μ νν λμΌν ν‘μ€μμ€μ΄ λ°μν©λλ€.
+
+κ·Έλ¬λ ν‘μ€μμ€μμ μνΈλ‘ λ€μ λ³νν μλ μμ΅λλ€.
+
+##### ν¨μ€μλ ν΄μ±μ μ¬μ©ν΄μΌ νλ μ΄μ
+
+λ°μ΄ν°λ² μ΄μ€κ° μ μΆλ κ²½μ° ν΄μ»€λ μ¬μ©μμ μΌλ° ν
μ€νΈ μνΈκ° μλλΌ ν΄μλ§ κ°κ² λ©λλ€.
+
+λ°λΌμ ν΄μ»€λ λ€λ₯Έ μμ€ν
μμ λμΌν μνΈλ₯Ό μ¬μ©νλ €κ³ μλν μ μμ΅λλ€(λ§μ μ¬μ©μκ° λͺ¨λ κ³³μμ λμΌν μνΈλ₯Ό μ¬μ©νλ―λ‘ μ΄λ μνν μ μμ΅λλ€).
+
+=== "Pνμ΄μ¬ 3.7 μ΄μ"
+
+ ```Python hl_lines="80-83"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "νμ΄μ¬ 3.10 μ΄μ"
+
+ ```Python hl_lines="78-81"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+#### `**user_dict`μ λν΄
+
+`UserInDB(**user_dict)`λ λ€μμ μλ―Ένλ€:
+
+*`user_dict`μ ν€μ κ°μ λ€μκ³Ό κ°μ ν€-κ° μΈμλ‘ μ§μ μ λ¬ν©λλ€:*
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ disabled = user_dict["disabled"],
+ hashed_password = user_dict["hashed_password"],
+)
+```
+
+!!! μ 보
+ `**user_dict`μ λν μμΈν μ€λͺ
μ [**μΆκ° λͺ¨λΈ** λ¬Έμ](../extra-models.md#about-user_indict){.internal-link target=_blank}λ₯Ό λ€μ μ½μ΄λ΄
μλ€.
+
+## ν ν° λ°ννκΈ°
+
+`token` μλν¬μΈνΈμ μλ΅μ JSON κ°μ²΄μ¬μΌ ν©λλ€.
+
+`token_type`μ΄ μμ΄μΌ ν©λλ€. μ¬κΈ°μλ "Bearer" ν ν°μ μ¬μ©νλ―λ‘ ν ν° μ νμ "`bearer`"μ¬μΌ ν©λλ€.
+
+κ·Έλ¦¬κ³ μ‘μΈμ€ ν ν°μ ν¬ν¨νλ λ¬Έμμ΄κ³Ό ν¨κ» `access_token`μ΄ μμ΄μΌ ν©λλ€.
+
+μ΄ κ°λ¨ν μμ μμλ μμ ν μμ νμ§ μκ³ , λμΌν `username`μ ν ν°μΌλ‘ λ°νν©λλ€.
+
+!!! ν
+ λ€μ μ₯μμλ ν¨μ€μλ ν΄μ± λ° <abbr title="JSON Web Tokens">JWT</abbr> ν ν°μ μ¬μ©νμ¬ μ€μ 보μ ꡬνμ λ³Ό μ μμ΅λλ€.
+
+ νμ§λ§ μ§κΈμ νμν μΈλΆ μ 보μ μ§μ€νκ² μ΅λλ€.
+
+=== "νμ΄μ¬ 3.7 μ΄μ"
+
+ ```Python hl_lines="85"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "νμ΄μ¬ 3.10 μ΄μ"
+
+ ```Python hl_lines="83"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+!!! ν
+ μ¬μμ λ°λΌ μ΄ μμ μ λμΌνκ² `access_token` λ° `token_type`μ΄ ν¬ν¨λ JSONμ λ°νν΄μΌ ν©λλ€.
+
+ μ΄λ μ½λμμ μ§μ μνν΄μΌ νλ©° ν΄λΉ JSON ν€λ₯Ό μ¬μ©ν΄μΌ ν©λλ€.
+
+ μ¬μμ μ€μνκΈ° μν΄ μ€μ€λ‘ μ¬λ°λ₯΄κ² μννκΈ° μν΄ κ±°μ μ μΌνκ² κΈ°μ΅ν΄μΌ νλ κ²μ
λλ€.
+
+ λλ¨Έμ§λ **FastAPI**κ° μ²λ¦¬ν©λλ€.
+
+## μμ‘΄μ± μ
λ°μ΄νΈνκΈ°
+
+μ΄μ μμ‘΄μ±μ μ
λ°μ΄νΈλ₯Ό ν κ²λλ€.
+
+μ΄ μ¬μ©μκ° νμ±νλμ΄ μλ *κ²½μ°μλ§* `current_user`λ₯Ό κ°μ Έμ¬ κ²λλ€.
+
+λ°λΌμ `get_current_user`λ₯Ό μμ‘΄μ±μΌλ‘ μ¬μ©νλ μΆκ° μ’
μμ± `get_current_active_user`λ₯Ό λ§λλλ€.
+
+μ΄λ¬ν μμ‘΄μ± λͺ¨λ, μ¬μ©μκ° μ‘΄μ¬νμ§ μκ±°λ λΉνμ±μΈ κ²½μ° HTTP μ€λ₯λ₯Ό λ°νν©λλ€.
+
+λ°λΌμ μλν¬μΈνΈμμλ μ¬μ©μκ° μ‘΄μ¬νκ³ μ¬λ°λ₯΄κ² μΈμ¦λμμΌλ©° νμ± μνμΈ κ²½μ°μλ§ μ¬μ©μλ₯Ό μ»μ΅λλ€:
+
+=== "νμ΄μ¬ 3.7 μ΄μ"
+
+ ```Python hl_lines="58-66 69-72 90"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "νμ΄μ¬ 3.10 μ΄μ"
+
+ ```Python hl_lines="55-64 67-70 88"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+!!! μ 보
+ μ¬κΈ°μ λ°ννλ κ°μ΄ `Bearer`μΈ μΆκ° ν€λ `WWW-Authenticate`λ μ¬μμ μΌλΆμ
λλ€.
+
+ λͺ¨λ HTTP(μ€λ₯) μν μ½λ 401 "UNAUTHORIZED"λ `WWW-Authenticate` ν€λλ λ°νν΄μΌ ν©λλ€.
+
+ λ² μ΄λ¬ ν ν°μ κ²½μ°(μ§κΈμ κ²½μ°) ν΄λΉ ν€λμ κ°μ `Bearer`μ¬μΌ ν©λλ€.
+
+ μ€μ λ‘ μΆκ° ν€λλ₯Ό 건λλΈ μ μμΌλ©° μ¬μ ν μλν©λλ€.
+
+ κ·Έλ¬λ μ¬κΈ°μμλ μ¬μμ μ€μνλλ‘ μ 곡λ©λλ€.
+
+ λν μ΄λ₯Ό μμνκ³ (νμ¬ λλ λ―Έλμ) μ¬μ©νλ λκ΅¬κ° μμ μ μμΌλ©°, νμ¬ λλ λ―Έλμ μμ νΉμ μμ μ μ μ λ€μκ² μ μ©ν κ²μ
λλ€.
+
+ κ·Έκ²μ΄ νμ€μ μ΄μ μ
λλ€ ...
+
+## νμΈνκΈ°
+
+λνν λ¬Έμ μ΄κΈ°: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+
+### μΈμ¦νκΈ°
+
+"Authorize" λ²νΌμ λλ¬λ΄
μλ€.
+
+μ격 μ¦λͺ
μ μ¬μ©ν©λλ€.
+
+μ μ λͺ
: `johndoe`
+
+ν¨μ€μλ: `secret`
+
+<img src="/img/tutorial/security/image04.png">
+
+μμ€ν
μμ μΈμ¦νλ©΄ λ€μκ³Ό κ°μ΄ νμλ©λλ€:
+
+<img src="/img/tutorial/security/image05.png">
+
+### μμ μ μ μ λ°μ΄ν° κ°μ Έμ€κΈ°
+
+μ΄μ `/users/me` κ²½λ‘μ `GET` μμ
μ μ§νν©μλ€.
+
+λ€μκ³Ό κ°μ μ¬μ©μ λ°μ΄ν°λ₯Ό μ»μ μ μμ΅λλ€:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false,
+ "hashed_password": "fakehashedsecret"
+}
+```
+
+<img src="/img/tutorial/security/image06.png">
+
+μ κΈ μμ΄μ½μ ν΄λ¦νκ³ λ‘κ·Έμμν λ€μ λμΌν μμ
μ λ€μ μλνλ©΄ λ€μκ³Ό κ°μ HTTP 401 μ€λ₯κ° λ°μν©λλ€.
+
+```JSON
+{
+ "detail": "Not authenticated"
+}
+```
+
+### λΉνμ±λ μ μ
+
+μ΄μ λΉνμ±λ μ¬μ©μλ‘ μλνκ³ , μΈμ¦ν΄λ΄
μλ€:
+
+μ μ λͺ
: `alice`
+
+ν¨μ€μλ: `secret2`
+
+κ·Έλ¦¬κ³ `/users/me` κ²½λ‘μ ν¨κ» `GET` μμ
μ μ¬μ©ν΄ λ΄
μλ€.
+
+λ€μκ³Ό κ°μ "Inactive user" μ€λ₯κ° λ°μν©λλ€:
+
+```JSON
+{
+ "detail": "Inactive user"
+}
+```
+
+## μμ½
+
+μ΄μ APIμ λν `username` λ° `password`λ₯Ό κΈ°λ°μΌλ‘ μμ ν 보μ μμ€ν
μ ꡬνν μ μλ λκ΅¬κ° μμ΅λλ€.
+
+μ΄λ¬ν λꡬλ₯Ό μ¬μ©νμ¬ λ³΄μ μμ€ν
μ λͺ¨λ λ°μ΄ν°λ² μ΄μ€ λ° λͺ¨λ μ¬μ©μ λλ λ°μ΄ν° λͺ¨λΈκ³Ό νΈνλλλ‘ λ§λ€ μ μμ΅λλ€.
+
+μ μΌν μ€μ μ μμ§ μ€μ λ‘ "μμ "νμ§ μλ€λ κ²μ
λλ€.
+
+λ€μ μ₯μμλ μμ ν ν¨μ€μλ ν΄μ± λΌμ΄λΈλ¬λ¦¬μ <abbr title="JSON Web Tokens">JWT</abbr> ν ν°μ μ¬μ©νλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€.