Passwordless Sign-in Flow
In-container passwordless sign-in uses the Client SDK to obtain a one-time code. The app backend then exchanges the code for the current user's identity. The SDK handles the client-side authorization request; application pages do not call the client authorization API directly.
Prerequisites
Configure the following items under "Internal Apps" in the admin console:
- The app is enabled, published, and has client display enabled.
- The desktop or mobile app entry point is configured.
- The actual application page is included in the in-container passwordless sign-in URL allowlist.
- The current user is within the app's visibility scope.
Flow
Application page
│ 1. SDK calls requestWorkbenchAuthCode() and obtains a one-time code
│ 2. Sends the code to the app backend over HTTPS
▼
App backend
│ 3. POST /auth/v1/oauth/token to obtain access_token
│ 4. POST /auth/v1/oauth/userinfo?access_token=... with the code
▼
App backend receives {userId, nickName, avatar} and creates its own session
Frontend example
<script src="/assets/sdk/twt-link-universal.umd.min.js"></script>
<script>
async function loginFromWorkbench() {
const sdk = window.__TWT_LINK__;
if (!sdk || !sdk.isTwtLinkPlateform()) {
window.location.href = "/login";
return;
}
const { code } = await sdk.requestWorkbenchAuthCode();
const response = await fetch("/api/workbench/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code }),
});
if (!response.ok) {
throw new Error("Sign-in failed. Request a new authorization code.");
}
}
loginFromWorkbench();
</script>
The frontend only obtains and submits the code. It must not store client_secret, access_token, or user identity data.
Backend API calls
1. Obtain an app token
The app backend uses the server-side client_id and client_secret to call the Token API:
POST /auth/v1/oauth/token
Content-Type: application/json
{
"client_id": "app ID",
"client_secret": "app secret",
"grant_type": "client_credentials"
}
Successful response:
{
"access_token": "app access token",
"expires_in": 7200
}
2. Get the current user's information
Use the returned access_token and the one-time frontend code to call the UserInfo API:
POST /auth/v1/oauth/userinfo?access_token=<access_token>
Content-Type: application/x-www-form-urlencoded
code=<code>
Successful response:
{
"userId": "10001",
"nickName": "Zhang San",
"avatar": "https://cdn.example.com/avatar/10001.png"
}
The code is single-use and becomes invalid immediately after exchange. Keep client_secret and access_token on the app backend; never expose them to the frontend.
Common errors
| HTTP status | Error code | Handling |
|---|---|---|
| 400 | INVALID_REQUEST | Check access_token, code, and the request format. |
| 400 | INVALID_GRANT | The code expired, was already used, or does not match the app; request a new code. |
| 401 | INVALID_TOKEN | Obtain a new app access_token. |
| 403 | USER_NOT_VISIBLE | Check whether the user is within the app's visibility scope. |
| 500 | SERVER_ERROR | Retry later. |