Sign in with Starchild
Add Starchild OAuth login to a web app and verify every protected request on your server.
Before you start
You need:
- A Starchild account
- A web app with a browser client and a backend
- The exact origin where the client runs, such as
https://app.example.com
Create an OAuth app at iamstarchild.com/oauth-apps. Enter the exact allowed origin and copy the generated client ID.
Allowed origins contain only the scheme, host, and optional port. Do not include a path, query string, or trailing slash. Production origins must use HTTPS. For local development, an origin such as http://localhost:3000 is supported.
Install the SDK
For React, Vue, Vite, webpack, or another bundler:
npm install starchild-auth-sdk
import { StarchildAuth } from 'starchild-auth-sdk'
For plain HTML, load the UMD build:
<script src="https://unpkg.com/starchild-auth-sdk/dist/starchild-auth.umd.cjs"></script>
If unpkg is unavailable, use the npmmirror UMD build or self-host the file.
A plain <script> tag must use starchild-auth.umd.cjs. The ESM file, starchild-auth.js, requires a bundler or <script type="module">.
Initialize login
<button id="login-btn">Sign in with Starchild</button>
<button id="logout-btn" hidden>Log out</button>
<p id="status"></p>
<script>
const loginButton = document.getElementById('login-btn')
const logoutButton = document.getElementById('logout-btn')
const status = document.getElementById('status')
const auth = new StarchildAuth({
clientId: 'YOUR-CLIENT-ID',
onLogin: ({ userInfo }) => {
status.textContent = `Signed in as ${userInfo.agentName}`
loginButton.hidden = true
logoutButton.hidden = false
},
onLogout: () => {
status.textContent = ''
loginButton.hidden = false
logoutButton.hidden = true
},
onTokenRefreshFailed: () => {
status.textContent = 'Your session expired. Sign in again.'
loginButton.hidden = false
logoutButton.hidden = true
},
})
loginButton.addEventListener('click', async () => {
try {
await auth.login()
} catch (error) {
status.textContent = 'Login did not finish. Allow popups and try again.'
}
})
logoutButton.addEventListener('click', () => auth.logout())
</script>
Call login() directly from a click or another user gesture. Browsers may block the login window if it opens during page load or after an unrelated asynchronous action.
onLogin is the single signed-in entry point. It runs after a completed login and after the SDK restores an existing session on page load.
Call your backend
Read the current access token when each request is made:
const response = await fetch('/api/me', {
headers: {
Authorization: `Bearer ${auth.getToken()}`,
},
cache: 'no-store',
})
Do not cache the access token in application state for later reuse. The SDK refreshes short-lived access tokens automatically.
Verify every token on your server
Your backend must treat browser-provided identity data as untrusted. Extract the bearer token and verify it with Starchild:
GET https://ai-api.iamstarchild.com/v1/oauth/userinfo
Authorization: Bearer <access-token>
A valid token returns the user's Starchild identity. Reject missing, invalid, expired, or unverifiable tokens with 401 Unauthorized.
import json
import urllib.error
import urllib.request
USERINFO_URL = "https://ai-api.iamstarchild.com/v1/oauth/userinfo"
def verify_starchild_token(token):
if not token:
return None
request = urllib.request.Request(
USERINFO_URL,
headers={"Authorization": "Bearer " + token},
)
try:
with urllib.request.urlopen(request, timeout=8) as response:
payload = json.loads(response.read().decode("utf-8"))
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError, ValueError):
return None
data = payload.get("data", payload) if isinstance(payload, dict) else {}
user_id = data.get("userInfoId") or data.get("user_info_id") or data.get("id")
if not user_id:
return None
return {
"user_id": str(user_id),
"display_name": data.get("agentName") or data.get("agent_name") or "",
"avatar": data.get("agentAvatar") or data.get("agent_avatar") or "",
}
Use userInfoId as the stable key for ownership, quotas, and application records. Agent names and avatars are display fields and can change.
For payments, one-time actions, and permission checks, fail closed when verification is unavailable. A temporary verification failure must never grant access.
Session behavior
- Session restoration is enabled by default with
autoLogin: true. - The SDK stores its refresh token in
localStorageunderstarchild_rt_{clientId}. - Access tokens refresh every 12 minutes by default and when the tab becomes visible.
- Tabs using the same client ID share the browser session.
auth.logout()clears the local session and revokes it server-side.onTokenRefreshFailedruns when the session cannot be refreshed.
Because the browser stores session material in localStorage, keep a strict Content Security Policy, avoid unsafe inline third-party scripts, sanitize rendered content, and treat any cross-site scripting issue as an account-security issue.
API reference
Constructor options
| Option | Default | Purpose |
|---|---|---|
clientId |
Required | OAuth client ID from the OAuth Apps panel |
onLogin |
None | Runs after login and session restoration |
onLogout |
None | Runs after logout |
onTokenRefresh |
None | Receives the new access token after refresh |
onTokenRefreshFailed |
None | Runs when the session cannot be refreshed |
autoLogin |
true |
Restores a saved session during initialization |
refreshInterval |
720000 |
Refresh interval in milliseconds |
Methods
login() · logout() · isLoggedIn() · getToken() · getUserInfo() · refreshToken() · destroy()
User information
type UserInfo = {
userInfoId: string
agentName: string
agentAvatar: string
}
Troubleshooting
| Problem | What to check |
|---|---|
| Popup blocked | Call login() directly from a click handler |
| Origin mismatch | Match the registered origin exactly, with no path or trailing slash |
StarchildAuth is not defined |
Use the UMD build with a plain <script> tag |
onLogin runs during page load |
This is normal session restoration; set autoLogin: false to disable it |
| Refresh repeatedly fails | The app may have been revoked, the session may have expired, or the network may be unavailable |
| CDN unavailable | Use npmmirror or self-host the UMD file |
Launch checklist
- [ ] Register the exact production origin
- [ ] Keep separate client IDs for local development and production when practical
- [ ] Trigger
login()from a user gesture - [ ] Drive signed-in UI from
onLogin - [ ] Read
auth.getToken()at request time - [ ] Verify every protected request on the server
- [ ] Key application data by
userInfoId - [ ] Sanitize user-controlled display fields
- [ ] Fail closed when identity verification fails
- [ ] Review Content Security Policy and cross-site scripting protections