The repository or configuration that created this release differ from a previous release. View details.
spakky-oauth
spakky-oauth는 application이 사용자를 대신해 외부 API를 부를 때 쓰는 OAuth 2.0 public client 플러그인입니다. Authorization code + PKCE로 token을 받고, 만료 전에 갱신하고, 로그아웃 시 폐기합니다.
spakky-oidc와 방향이 반대입니다. spakky-oidc는 들어오는 bearer token을 검증하고,
spakky-oauth는 나가는 호출에 쓸 token을 얻어 보관합니다.
제공 기능
- Authorization code flow 시작:
state, PKCES256challenge,openidscope가 있으면nonce생성 - Callback code 교환과 token 저장
- 만료
refresh_leeway_seconds전 갱신, refresh token 회전 반영 - 같은 주체의 동시 갱신을 하나로 묶는 process-local 잠금
- 다른 instance가 먼저 회전해 저장한 token 재사용 (best-effort; 분산 잠금은 아님)
- Revocation endpoint 호출과 local token 삭제
포함하지 않는 것
- 로그인·callback HTTP route. Application의 inbound adapter(FastAPI 등)가
OAuthClient를 호출합니다. - ID token 서명·claim 검증.
OAuthAuthorizationResult가tokens.id_token과nonce를 돌려주므로 application이 검증합니다. - Confidential client 인증(
client_secret), device code, client credentials grant. - 여러 process 사이의 분산 잠금. 저장소 구현이 필요하면 직접 제공합니다.
설치
pip install spakky-oauth
구성
OAuthConfig는 SPAKKY_OAUTH__ prefix의 환경 변수에서 읽습니다.
export SPAKKY_OAUTH__CLIENTS='{
"example": {
"authorization_endpoint": "https://auth.example.test/authorize",
"token_endpoint": "https://auth.example.test/token",
"revocation_endpoint": "https://auth.example.test/revoke",
"client_id": "my-app",
"scopes": ["openid", "offline_access"],
"token_parameters": {"resource": "https://api.example.test"}
}
}'
OAuthConfig
| Field | 기본값 | 책임 |
|---|---|---|
clients |
{} |
이름별 OAuthClientRegistration |
http_timeout_seconds |
20.0 |
token·revocation 요청 timeout |
refresh_leeway_seconds |
90.0 |
만료 이만큼 전에 갱신 |
authorization_ttl_seconds |
600.0 |
시작한 authorization이 callback을 기다리는 시간 |
OAuthClientRegistration
| Field | 기본값 | 책임 |
|---|---|---|
authorization_endpoint |
필수 | 사용자를 보낼 authorization URL |
token_endpoint |
필수 | code 교환과 refresh endpoint |
revocation_endpoint |
None |
없으면 revoke()는 local token만 삭제 |
client_id |
필수 | public client id |
scopes |
() |
요청할 scope |
authorization_parameters |
{} |
authorization 요청에 더할 parameter |
token_parameters |
{} |
code 교환과 refresh 요청에 더할 parameter |
Endpoint는 https여야 하며 loopback host에 한해 http를 허용합니다. 추가 parameter는
client_id, state, code_verifier 같은 protocol field를 덮어쓸 수 없습니다.
저장소 등록
Plugin은 OAuthConfig와 OAuthClient만 등록합니다. Token과 authorization state 저장소는
application이 Pod로 등록합니다. 개발과 테스트에는 in-memory 구현을 쓸 수 있습니다.
from spakky.core.pod.annotations.pod import Pod
from spakky.plugins.oauth.store import (
InMemoryOAuthAuthorizationStateStore,
InMemoryOAuthTokenStore,
)
@Pod()
class DevTokenStore(InMemoryOAuthTokenStore): ...
@Pod()
class DevStateStore(InMemoryOAuthAuthorizationStateStore): ...
운영에서는 IOAuthTokenStore와 IOAuthAuthorizationStateStore를 database나 cache로 구현합니다.
In-memory 구현은 만료된 authorization을 지우지 않으므로 운영에 쓰지 않습니다.
OAuthTokenSet과 OAuthPendingAuthorization의 token과 code_verifier는 SecretStr입니다.
model_dump_json()은 이 값을 **********로 바꾸므로 그대로 저장하면 token을 잃습니다.
저장소 구현은 get_secret_value()로 값을 꺼내 직접 직렬화하고, 암호화도 책임집니다.
사용법
from spakky.plugins.oauth.client import OAuthClient
from spakky.plugins.oauth.error import OAuthAuthorizationRequiredError
async def login(oauth: OAuthClient, user_id: str) -> str:
request = await oauth.begin_authorization(
"example",
user_id,
"https://app.example.test/auth/callback",
)
return request.url # 사용자를 이 URL로 redirect
async def callback(oauth: OAuthClient, state: str, code: str) -> None:
# 먼저 state가 이 브라우저 session에서 시작한 값인지 대조합니다.
result = await oauth.complete_authorization(state, code)
# result.tokens.id_token과 result.nonce로 ID token을 검증합니다.
async def call_api(oauth: OAuthClient, user_id: str) -> str:
try:
return await oauth.access_token("example", user_id)
except OAuthAuthorizationRequiredError:
# 다시 로그인이 필요합니다.
raise
Callback은 반드시 로그인한 session에 묶습니다. begin_authorization()이 돌려준 state를
사용자의 브라우저 session에 저장하고, callback에서 받은 state가 그 값과 같은지 확인한 뒤
complete_authorization()을 호출합니다. 이 확인이 없으면 공격자가 자기 주체로 시작한 URL을
피해자에게 열게 해 피해자의 token을 공격자 주체 아래 저장할 수 있습니다.
Resource server가 token을 401로 거절하면 그 token을 넘겨 한 번 갱신합니다. 저장된 token이 이미 다른 token으로 바뀌었다면 갱신하지 않고 새 token을 돌려줍니다.
token = await oauth.access_token("example", user_id, rejected_token=token)
Sign-in마다 client id를 발급하는 server는 begin_authorization(..., client_id=...)와
complete_authorization(..., client_id=...)로 실제 client id를 전달합니다. 요청별 추가
parameter는 begin_authorization(..., parameters={...})로 넘깁니다.
에러
| 에러 | 의미 |
|---|---|
OAuthClientNotConfiguredError |
이름에 해당하는 registration이 없음 |
OAuthAuthorizationRequestError |
요청별 parameter가 protocol field를 덮어쓰거나 client_id override가 비어 있음 |
OAuthAuthorizationStateError |
callback state를 모르거나 이미 썼거나 만료됨 |
OAuthAuthorizationRequiredError |
token이 없거나 grant가 거절되어 다시 로그인해야 함 |
OAuthTokenEndpointError |
token endpoint가 grant 거절이 아닌 이유로 실패 |
OAuthTokenResponseError |
token 응답이 사용할 수 있는 bearer token이 아님 |
OAuthTransportError |
authorization server에 연결하지 못함 |
OAuthRevocationError |
local token은 삭제했지만 server에 닿지 못했거나 server가 폐기를 확인하지 않음 |
Token endpoint가 error="invalid_grant"로 답한 경우에만 OAuthAuthorizationRequiredError를 올립니다.
그 밖의 4xx/5xx는 OAuthTokenEndpointError입니다. 두 경우 모두 access_token()은 저장된 token을
지우지 않습니다. 다른 instance가 방금 회전해 저장하려는 token을 지우지 않기 위해서입니다.
다시 로그인시키기 전에 저장분을 비우려면 revoke()를 호출합니다.
라이선스
MIT
Metadata
Release files for spakky-oauth 11.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Change of provenance
The repository or configuration that created these release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| spakky_oauth-11.1.0.tar.gz | 12.7 kB | With provenance | Details for spakky_oauth-11.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| spakky_oauth-11.1.0-py3-none-any.whl | Python 3 | none | any | Details for spakky_oauth-11.1.0-py3-none-any.whl |
Total release size: 27.7 kB
Release files / spakky_oauth-11.1.0.tar.gz
Change of provenance
This file belongs to a release with changed provenance: the repository or configuration that created the release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
| Download URL | spakky_oauth-11.1.0.tar.gz |
|---|---|
| Size | 12.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1de4e8b92572cd3a2cd72f5fea705810f7b185439f4fca347f58dab6105b5f73
|
|
BLAKE2b-256 checksum How to use checksums |
9e76e1cc26e5e4a5a4c1cd4d5db5309b338ee5de378b479f30c061bed1205857
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logRelease files / spakky_oauth-11.1.0-py3-none-any.whl
Change of provenance
This file belongs to a release with changed provenance: the repository or configuration that created the release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
| Download URL | spakky_oauth-11.1.0-py3-none-any.whl |
|---|---|
| Size | 15.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2a14f9ccca83ce9660f2d47d7388098f74643c65342174ff460ecec80da6a0c1
|
|
BLAKE2b-256 checksum How to use checksums |
562b5e711979d2e9917858c27715e21954411f18245dda1fd742a4864b6512b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logSecurity for spakky-oauth 11.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Change of provenance
The configuration that created this release differs from a previous release.
While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.
Attestation for spakky_oauth-11.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.