813da349ec
fix(api,web): post-review hardening for OAuth device flow
...
- api: account-flow stores subject_issuer="dify:account" sentinel
instead of NULL so the rotate-in-place unique index collides as
intended (Postgres treats NULLs as distinct in unique indices).
mint_oauth_token validates prefix-specific issuer rules.
- api: enterprise_only inverts to an allowlist (ACTIVE / EXPIRING) so
any future LicenseStatus value defaults to denial.
- api: consume_on_poll moved to a single Lua script (GET + status-check
+ DEL) so concurrent pollers can't both observe APPROVED.
- web: typed DeviceFlowError + central error-copy mapping; page
surfaces rate_limited / lookup_failed view states; URL params
scrubbed after consumption (RFC 8628 §5.4).
2026-04-26 23:05:07 -07:00
fe8510ad1a
feat(api,web): OAuth 2.0 device flow + bearer auth (RFC 8628)
...
Adds a CLI-friendly authorization flow so difyctl (and future
non-browser clients) can obtain user-scoped tokens without copy-
pasting cookies or raw API keys. Two grant paths share one device
flow surface:
1. Account branch — user signs in via the existing /signin
methods, /device page calls console-authed approve, mints a
dfoa_ token tied to (account_id, tenant).
2. External-SSO branch (EE) — /v1/oauth/device/sso-initiate signs
an SSOState envelope, hands off to Enterprise's external ACS,
receives a signed external-subject assertion, mints a dfoe_
token tied to (subject_email, subject_issuer).
API surface (all under /v1, EE-only endpoints 404 on CE):
POST /v1/oauth/device/code — RFC 8628 start
POST /v1/oauth/device/token — RFC 8628 poll
GET /v1/oauth/device/lookup — pre-validate user_code
GET /v1/oauth/device/sso-initiate — SSO branch entry
GET /v1/device/sso-complete — SSO callback sink
GET /v1/oauth/device/approval-context — /device cookie probe
POST /v1/oauth/device/approve-external — SSO approve
GET /v1/me — bearer subject lookup
DELETE /v1/oauth/authorizations/self — self-revoke
POST /console/api/oauth/device/approve — account approve
POST /console/api/oauth/device/deny — account deny
Core primitives:
- libs/oauth_bearer.py: prefix-keyed TokenKindRegistry +
BearerAuthenticator + validate_bearer decorator. Two-tier scope
(full vs apps:run) stamped from the registry, never from the DB.
- libs/jws.py: HS256 compact JWS keyed on the shared Dify
SECRET_KEY — same key-set verifies the SSOState envelope, the
external-subject assertion (minted by Enterprise), and the
approval-grant cookie.
- libs/device_flow_security.py: enterprise_only gate, approval-
grant cookie mint/verify/consume (Path=/v1/oauth/device,
HttpOnly, SameSite=Lax, Secure follows is_secure()), anti-
framing headers.
- libs/rate_limit.py: typed RateLimit / RateLimitScope dispatch
with composite-key buckets; both decorator + imperative form.
- services/oauth_device_flow.py: Redis state machine (PENDING ->
APPROVED|DENIED with atomic consume-on-poll), token mint via
partial unique index uq_oauth_active_per_device (rotates in
place), env-driven TTL policy.
Storage: oauth_access_tokens table with partial unique index on
(subject_email, subject_issuer, client_id, device_label) WHERE
revoked_at IS NULL. account_id NULL distinguishes external-SSO
rows. Hard-expire is CAS UPDATE (revoked_at + nullify token_hash)
so audit events keep their token_id. Retention pruner DELETEs
revoked + zombie-expired rows past OAUTH_ACCESS_TOKEN_RETENTION_DAYS.
Frontend: /device page with code-entry, chooser (account vs SSO),
authorize-account, authorize-sso views. SSO branch detaches from
the URL user_code and reads everything from the cookie via
/approval-context. Anti-framing headers on all responses.
Wiring: ENABLE_OAUTH_BEARER feature flag; ext_oauth_bearer binds
the authenticator at startup; clean_oauth_access_tokens_task
scheduled in ext_celery.
Spec: docs/specs/v1.0/server/{device-flow,tokens,middleware,security}.md
2026-04-26 20:06:43 -07:00
3193e8a712
chore: reorg imports ( #35308 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-16 08:50:02 +00:00
7e7b27fdec
refactor: replace bare dict with dict[str, Any] in response converter… ( #35212 )
...
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-14 19:45:04 +00:00
8dd4473432
refactor(auth): standardize failed login audit logging ( #35054 )
2026-04-13 12:26:13 +00:00
e37aaa482d
refactor: migrate apikey from marshal_with/api.model to Pydantic BaseModel ( #34932 )
...
Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com >
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-13 05:18:42 +00:00
bcd738d2e6
fix: fix orm_exc.DetachedInstanceError ( #34904 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-10 07:13:59 +00:00
f8f7b0ec1a
refactor(api): deduplicate shared auth request payloads into auth_entities.py ( #34694 )
2026-04-07 22:51:11 +00:00
89e23456f0
refactor(api): type invitation detail with InvitationDetailDict TypedDict ( #34613 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-07 01:03:31 +00:00
8f9dbf269e
chore(api): align Python support with 3.12 ( #34419 )
...
Co-authored-by: Asuka Minato <i@asukaminato.eu.org >
2026-04-02 05:07:32 +00:00
40591a7c50
refactor(api): use standalone graphon package ( #34209 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-03-27 21:05:32 +00:00
52e7492cbc
refactor(api): rename dify_graph to graphon ( #34095 )
2026-03-25 21:58:56 +08:00
ceb2e10179
refactor: use sessionmaker().begin() in console auth controllers ( #33966 )
2026-03-24 23:59:21 +09:00
244f9e0c11
fix: handle null email/name from GitHub API for private-email users ( #33882 )
...
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com >
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com >
2026-03-23 14:53:03 +08:00
4fd6b52808
refactor(api): move model_runtime into dify_graph ( #32858 )
2026-03-02 20:15:32 +08:00
ac222a4dd4
refactor: port api/controllers/console/app/audio.py api/controllers/console/app/message.py api/controllers/console/auth/data_source_oauth.py api/controllers/console/auth/forgot_password.py api/controllers/console/workspace/endpoint.py ( #30680 )
2026-02-02 18:03:07 +09:00
3216b67bfa
refactor: examples of use match case ( #31312 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-01 19:25:54 +09:00
72ce6ca437
feat: implement workspace permission checks for member invitations an… ( #31202 )
2026-01-18 19:35:50 -08:00
491e1fd6a4
chore: case insensitive email ( #29978 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: -LAN- <laipz8200@outlook.com >
2026-01-13 15:42:44 +08:00
f3ca8be9f9
refactor: clean type: ignore comments in login.py and template_transformer.py ( #30510 )
...
Signed-off-by: majiayu000 <1835304752@qq.com >
2026-01-06 14:33:27 +08:00
3a59ae9617
feat: add oauth_new_user flag for frontend when user oauth login ( #30370 )
...
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: hj24 <mambahj24@gmail.com >
2025-12-31 10:10:58 +08:00
d005689d0a
chore: remove unused login call from activation flow ( #30017 )
2025-12-23 12:26:52 +08:00
b7649f61f8
fix: Login secret text transmission ( #29659 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Joel <iamjoel007@gmail.com >
Co-authored-by: -LAN- <laipz8200@outlook.com >
2025-12-16 16:55:51 +08:00
7396eba1af
refactor: port reqparse to Pydantic model ( #28949 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
2025-12-05 13:05:53 +09:00
e0824c2d93
api -> console_ns ( #28246 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-24 10:04:11 +08:00
1a2f8dfcb4
use deco ( #28153 )
...
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-21 14:25:53 +08:00
fa6d03c979
Fix/refresh token ( #27381 )
2025-10-24 13:09:34 +08:00
2bcf96565a
Feature:during account initialization, set the interface language to be consistent with the display language( #27029 ) ( #27042 )
...
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
2025-10-21 15:53:12 +08:00
ff9b74efeb
fix: remove login status api ( #27177 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-21 13:24:57 +08:00
9a5f214623
refactor: replace localStorage with HTTP-only cookies for auth tokens ( #24365 )
...
Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com >
Signed-off-by: lyzno1 <yuanyouhuilyz@gmail.com >
Signed-off-by: kenwoodjw <blackxin55+@gmail.com >
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Yunlu Wen <wylswz@163.com >
Co-authored-by: Joel <iamjoel007@gmail.com >
Co-authored-by: GareArc <chen4851@purdue.edu >
Co-authored-by: NFish <douxc512@gmail.com >
Co-authored-by: Davide Delbianco <davide.delbianco@outlook.com >
Co-authored-by: minglu7 <1347866672@qq.com >
Co-authored-by: Ponder <ruan.lj@foxmail.com >
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: heyszt <270985384@qq.com >
Co-authored-by: Asuka Minato <i@asukaminato.eu.org >
Co-authored-by: Guangdong Liu <liugddx@gmail.com >
Co-authored-by: Eric Guo <eric.guocz@gmail.com >
Co-authored-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com >
Co-authored-by: XlKsyt <caixuesen@outlook.com >
Co-authored-by: Dhruv Gorasiya <80987415+DhruvGorasiya@users.noreply.github.com >
Co-authored-by: crazywoola <427733928@qq.com >
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com >
Co-authored-by: hj24 <mambahj24@gmail.com >
Co-authored-by: GuanMu <ballmanjq@gmail.com >
Co-authored-by: 非法操作 <hjlarry@163.com >
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
Co-authored-by: Tonlo <123lzs123@gmail.com >
Co-authored-by: Yusuke Yamada <yamachu.dev@gmail.com >
Co-authored-by: Novice <novice12185727@gmail.com >
Co-authored-by: kenwoodjw <blackxin55+@gmail.com >
Co-authored-by: Ademílson Tonato <ademilsonft@outlook.com >
Co-authored-by: znn <jubinkumarsoni@gmail.com >
Co-authored-by: yangzheli <43645580+yangzheli@users.noreply.github.com >
2025-10-19 21:29:04 +08:00
4488c090b2
fluent api ( #27093 )
...
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
2025-10-19 12:54:41 +09:00
cced33d068
use deco to avoid current_user ( #26077 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-16 15:45:51 +09:00
0a6b78f883
Use hook to get userid ( #26839 )
...
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-14 09:20:37 +08:00
1bd621f819
remove .value ( #26633 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-11 09:08:29 +08:00
095c56a646
refactor(router): apply ns.route style ( #26339 )
2025-09-28 13:37:06 +08:00
8940decd1b
more httpx ( #25651 )
...
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-09-22 23:07:09 +08:00
bab4975809
chore: add ast-grep rule to convert Optional[T] to T | None ( #25560 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-15 13:06:33 +08:00
c2fcd2895b
Feat/email register refactor ( #25369 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
Co-authored-by: Joel <iamjoel007@gmail.com >
2025-09-12 10:24:54 +08:00
b51c724a94
refactor: Migrate part of the console basic API module to Flask-RESTX ( #24732 )
...
Signed-off-by: -LAN- <laipz8200@outlook.com >
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com >
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
Co-authored-by: -LAN- <laipz8200@outlook.com >
2025-09-10 12:15:47 +08:00
08dd3f7b50
Fix basedpyright type errors ( #25435 )
...
Signed-off-by: -LAN- <laipz8200@outlook.com >
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-10 01:54:26 +08:00
ea61420441
Revert "feat: email register refactor" ( #25367 )
2025-09-08 19:20:09 +08:00
860ee20c71
feat: email register refactor ( #25344 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
2025-09-08 17:51:43 +08:00
f6059ef389
add more typing ( #24949 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-08 10:40:00 +08:00
a9c7669c16
chore: comply to RFC 6750 and improve bearer token split ( #24955 )
2025-09-03 22:29:08 +08:00
9d5956cef8
[Chore/Refactor] Switch from MyPy to Basedpyright for type checking ( #25047 )
...
Signed-off-by: -LAN- <laipz8200@outlook.com >
2025-09-03 11:52:26 +08:00
7b379e2a61
chore: apply ty checks on api code with script and ci action ( #24653 )
2025-09-02 16:05:13 +08:00
2e6e414a9e
the conversion OAuthGrantType(parsed_args["grant_type"]) can raise ValueError for invalid values which is not caught and will produce a 500 ( #24854 )
2025-09-01 10:05:54 +08:00
c45d676477
remove duplicated authorization header handling and bearer should be case-insensitive ( #24852 )
2025-09-01 10:05:19 +08:00
f32e176d6a
feat: oauth provider ( #24206 )
...
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yessenia <yessenia.contact@gmail.com >
2025-08-29 14:10:51 +08:00
fa753239ad
Refactor: use logger = logging.getLogger(__name__) in logging ( #24515 )
...
Co-authored-by: Yongtao Huang <99629139+hyongtao-db@users.noreply.github.com >
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com >
2025-08-26 18:10:31 +08:00