Skip to content

Auth Module (Login/User)

The Auth module is built on top of @makeblock/passport-client, so developers do not need to implement login logic themselves.

API List

MethodReturn ValueDescription
sdk.auth.getStatus()AuthStatusSynchronously get the current login status from local cache
sdk.auth.login()Promise<UserInfo>Open the login modal and return user info on success
sdk.auth.logout()Promise<void>Log out and clear the local token
sdk.auth.onChange(callback)() => voidListen for status changes and return an unsubscribe function
sdk.auth.getToken()stringGet the current uToken; returns an empty string when not logged in
sdk.auth.syncToken(token)Promise<AuthStatus>Persist an external token and refresh the login state

Detailed Usage

Get Current Status

typescript
const status = sdk.auth.getStatus()
// { isLogin: boolean, userInfo: UserInfo | null }

if (status.isLogin) {
  console.log('Username:', status.userInfo!.userName)
  console.log('Avatar:', status.userInfo!.headpic)
  console.log('Email:', status.userInfo!.email)
  console.log('Roles:', status.userInfo!.roleList)
  console.log('Is community admin:', status.userInfo!.isCommunityAdmin)
}

Log In with Modal

typescript
try {
  const userInfo = await sdk.auth.login()
  console.log('Login successful:', userInfo.userName)
  console.log('Roles:', userInfo.roleList)
  console.log('Is community admin:', userInfo.isCommunityAdmin)
} catch (err) {
  // The user closed the modal or login failed
  console.log('Login cancelled or failed:', err.message)
}

Log Out

typescript
await sdk.auth.logout()
// The local token has been cleared, and passport-client has called the logout API

Listen for Status Changes

typescript
const unsubscribe = sdk.auth.onChange((status) => {
  if (status.isLogin) {
    showUserInfo(status.userInfo!)
  } else {
    showLoginButton()
  }
})

// Unsubscribe when the component is unmounted
unsubscribe()

Get the Raw Token

typescript
const token = sdk.auth.getToken()
// Can be used for custom API requests implemented by developers

Sync an External Token

typescript
await sdk.auth.syncToken(token)
// The token is persisted to local storage and the login state is refreshed

await sdk.auth.syncToken('')
// Empty token clears local login status and returns { isLogin: false, userInfo: null }

Studio Embedded Login Sync

After initialization, the SDK automatically tries to sync the login state injected by xTool Studio. Generators do not need to call syncToken() manually for this case:

  • Wujie micro frontend: reads window.$wujie.props.token and listens for the UserStateChanged event on window.$wujie.bus.
  • iframe embedding: reads the initial value from data-initial on window.frameElement and listens for postMessage({ eventName: 'UserStateChanged', payload: { token } }) from trusted Studio origins, including Studio Electron's atomm://renderer.
  • When Studio sends an empty token, the SDK clears the local login state and triggers onChange().

This sync reuses the internal syncToken() flow: write the utoken cookie, fetch user info through passport-client, fetch roles, and emit the auth status change.

Role Information

After login or syncToken(), the SDK also fetches the user's role list from /efficacy/v1/roles?d=xtool.

typescript
const userInfo = await sdk.auth.login()

console.log(userInfo.roleList)
// Example: [{ code: 'community_admin', name: 'Community Admin' }]

console.log(userInfo.isCommunityAdmin)
// true when roleList contains code === 'community_admin'

UserInfo Type

typescript
interface UserRole {
  code: string
  [key: string]: unknown
}

interface UserInfo {
  uid: number              // User ID
  uuid: string             // User UUID
  userName: string         // User name (note: not nickname)
  headpic: string          // Avatar URL
  email: string            // Email
  phoneNumber: string      // Phone number
  phoneZone: string        // Phone country/region code
  gender: number           // Gender: 0=unknown / 1=male / 2=female
  signature: string        // Personal signature
  createTime: number       // Account creation time (Unix seconds)
  roleList: UserRole[]     // User roles from /efficacy/v1/roles?d=xtool
  isCommunityAdmin: boolean // Whether roleList contains code === 'community_admin'
}

interface AuthStatus {
  isLogin: boolean
  userInfo: UserInfo | null
}

Internal Login Flow

① Call sdk.auth.login()
② passport-client.openModal() opens the login modal
③ The user logs in with account/password or QR code
④ The callback receives the token → setToken(appKey, token) writes it to local storage
⑤ passportClient.userInfo() fetches user info to verify token validity
⑥ /efficacy/v1/roles?d=xtool fetches the role list
⑦ Internal _setLoginStatus() updates state and triggers onChange callbacks
⑧ login() resolves with UserInfo

Automatic Token Restore

When the SDK initializes, it runs local restore followed by Studio host sync:

  1. Read the token from local storage
  2. If a token exists, call passportClient.userInfo() to validate it
  3. If validation succeeds, set the login status and trigger onChange
  4. If validation fails, clear the invalid token
  5. If the current page is embedded in xTool Studio, read the Studio initial token and let the Studio login state win
  6. After initialization, keep listening for Studio UserStateChanged events so the generator stays aligned with the Studio host

WARNING

Restore is asynchronous. After init() returns, getStatus() may still report logged out, so listen to onChange for the final state.

Error Handling Notes

  • login() rejects when the modal callback returns an empty token.
  • syncToken() clears local state and returns logged-out status when token is empty.
  • syncToken() rethrows errors from user-info fetch after clearing local login state.
  • logout() always clears local state even if remote logout fails.

MIT Licensed