Expand description
DingTalk authentication plugin (dingtalk-auth).
Validates a DingTalk authorization code by exchanging it, through
DingTalk’s OAuth API, for the calling user’s identity, then attaches that
identity to the request for downstream nodes. A request whose code is
missing or that DingTalk actively rejects is denied with a 401 on the
denied port; a DingTalk callout that fails outright (network error,
non-200, unparseable body) is a genuine infrastructure failure and stays
on the error port.
§Ported subset / deviations from APISIX
APISIX’s dingtalk-auth is a session plugin: on the first request it
reads a code, calls DingTalk, then stores the resolved userinfo in an
encrypted dingtalk_session cookie so later requests skip the callout, and
it 302-redirects to redirect_uri when no code and no session are present.
That session machinery is now restored on an opt-in basis, sharing the
same cookie /
server-store primitives as
cas-auth/openid-connect/authz-casdoor:
- Stateless (default) — when no
session.secretis configured the node behaves exactly as before: every request must carry a code, which is validated against DingTalk on each request. No cookie is read or set. - Session (opt-in) — set
session.secret(orsession_secret) to turn the flow back on: strip any client-suppliedx-userinfo, then read thedingtalk_sessioncookie (cookie mode: the userinfo JSON is sealed directly in the cookie; redis mode viasession.storage: redis+session.store: <name>: the cookie carries a bare id, the sealed userinfo lives server-side). A valid session attaches identity straight from the stored payload — no DingTalk callout. An undecodable payload (corrupt/stale format) is destroyed and treated as no session rather than failing the request. No session and no code 302-redirects to the requiredredirect_uri(theredirectport). A code present runs the existing token+userinfo callouts unchanged, then establishes a new session (payload = the userinforesultJSON; subject =useridelseunionidelse empty; ttl =session.cookie.lifetime, APISIX’scookie_expires_in, default86400) and 302-redirects (theredirectport) to the current URL with thecodequery parameter stripped, carrying the sessionSet-Cookie— the graph wiressuccessstraight toupstream.in, which replacesctx.response.headerswholesale, so a Set-Cookie attached on that path would never reach the browser. The browser’s follow-up request then hits the session-read fast path above and attaches identity. A session-store outage is a503(SESSION_STORE_ERROR) on theerrorport, never a silent re-login. The app-level access token is still cached in-process (7000s TTL, matching APISIX’slrucache).
Remaining deviation: secret_fallbacks (APISIX’s multi-secret key
rotation) is not supported — the sealer is a single session.secret,
same as every other session plugin in this codebase.
Structs§
- Dingtalk
Auth Plugin - Authenticates requests by resolving a DingTalk authorization code to a
DingTalk user via the OAuth
accessToken+getuserinfoAPIs. - Dingtalk
Session 🔒 - Session-mode settings (present when
session.secretis configured).
Enums§
- Dingtalk
Error 🔒 - Outcome of resolving a DingTalk code into userinfo.
Unauthorizedis a deliberate denial (exitsdenied,401);Upstreamis a genuine callout failure (exitserror).
Constants§
- ACCESS_
TOKEN_ 🔒TTL - DingTalk access tokens live 7200s; cache slightly shorter to avoid using a token that expires mid-flight (matches APISIX’s cache TTL).
- DEFAULT_
TOKEN_ 🔒URL - DEFAULT_
USERINFO_ 🔒URL
Functions§
- append_
query 🔒 - Appends
key=valuetourl, choosing?or&as needed. - attach_
identity 🔒 - Copies the resolved identity into
context.messageand optionally theX-Userinforequest header. - parse_
access_ 🔒token - Parses the
accessTokenfrom DingTalk’s token-endpoint response. - parse_
userinfo 🔒 - Parses DingTalk’s
getuserinforesponse, returning theresultobject onerrcode == 0and anDingtalkError::Unauthorizedotherwise. - redirect_
target 🔒 - Rebuilds the current request’s path+query with the
codequery parameter stripped, for the post-establish redirect (so the browser’s follow-up GET doesn’t resubmit the one-time code). If the code was read from the header rather than the query string, there is nothing to strip and the query comes back unchanged. Mirrorsauthz_casdoor.rs::reconstruct_uri. - require_
string 🔒 - Extracts a required string config key.
- session_
cookie_ 🔒str - Reads a string field from nested
session.cookie.<key>, falling back to the flatsession_cookie_<key>form (used by the UI schema). - session_
cookie_ 🔒u64 - Reads a u64 field from nested
session.cookie.<key>, falling back to the flatsession_cookie_<key>form (used by the UI schema). - session_
secret 🔒 - Reads the session secret from
session_secretor nestedsession.secret. - urlencode 🔒
- Minimal percent-encoding for query values (access tokens are URL-safe-ish
but may contain
+/=).