Overview
The Timeback SDK supports two identity modes.SSO
Use Timeback as your identity provider
Custom
Use your existing auth system
SSO Mode
SSO mode uses Timeback as the identity provider via OIDC. The SDK automatically resolves the Timeback user by email and returnsTimebackAuthUser.
import { createTimeback } from '@timeback/sdk'
export const timeback = await createTimeback({
env: 'staging',
api: {
clientId: process.env.TIMEBACK_API_CLIENT_ID!,
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET!,
},
identity: {
mode: 'sso',
clientId: process.env.AWS_COGNITO_CLIENT_ID!,
clientSecret: process.env.AWS_COGNITO_CLIENT_SECRET!,
onCallbackSuccess: async ({ user, idp, state, redirect }) => {
// user.id is the timebackId
// user.email, user.name come from the user's Timeback profile
// user.claims contains IdP data (sub, firstName, lastName, pictureUrl)
await setSession({ id: user.id, email: user.email })
return redirect(state?.returnTo ?? '/')
},
onCallbackError: ({ error, errorCode, redirect }) => {
console.error('SSO Error:', errorCode, error.message)
return redirect('/?error=sso_failed')
},
getUser: () => getCurrentSession(),
},
})
from timeback.server import (
create_server, TimebackConfig, ApiCredentials, SsoIdentityConfig,
)
async def get_user(request):
session = await get_session(request)
return {"id": session.user_id, "email": session.email}
async def on_callback_success(ctx):
# ctx.user["id"] is the timebackId
# ctx.user["email"], ctx.user["name"] come from the user's Timeback profile
await set_session(id=ctx.user["id"], email=ctx.user["email"])
return ctx.redirect(ctx.state.get("return_to", "/"))
def on_callback_error(ctx):
return ctx.redirect("/?error=sso_failed")
timeback = create_server(TimebackConfig(
env="staging",
api=ApiCredentials(
client_id=os.environ["TIMEBACK_API_CLIENT_ID"],
client_secret=os.environ["TIMEBACK_API_CLIENT_SECRET"],
),
identity=SsoIdentityConfig(
mode="sso",
client_id=os.environ["TIMEBACK_SSO_CLIENT_ID"],
client_secret=os.environ["TIMEBACK_SSO_CLIENT_SECRET"],
get_user=get_user,
on_callback_success=on_callback_success,
on_callback_error=on_callback_error,
),
))
user object in onCallbackSuccess has this structure:
interface TimebackAuthUser {
id: string // Timeback user ID
email: string
name?: string
school?: { id: string; name: string }
grade?: number
claims: {
sub: string
email: string
firstName?: string
lastName?: string
pictureUrl?: string
}
}
Custom Mode
Use custom mode when your app has its own authentication system.import { createTimeback } from '@timeback/sdk'
export const timeback = await createTimeback({
env: 'staging',
api: {
clientId: process.env.TIMEBACK_API_CLIENT_ID!,
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET!,
},
identity: {
mode: 'custom',
getEmail: async req => {
const session = await getSession(req)
// Return the email from your existing auth system
return session?.email
},
},
})
from timeback.server import (
create_server, TimebackConfig, ApiCredentials, CustomIdentityConfig,
)
async def get_user_email(request):
session = await get_session(request)
# Return the email from your existing auth system
return session.email if session else None
timeback = create_server(TimebackConfig(
env="staging",
api=ApiCredentials(
client_id=os.environ["TIMEBACK_API_CLIENT_ID"],
client_secret=os.environ["TIMEBACK_API_CLIENT_SECRET"],
),
identity=CustomIdentityConfig(
mode="custom",
get_email=get_user_email,
),
))
Identity-Only Mode
If you need only SSO, usecreateTimebackIdentity():
lib/timeback.ts
import { createTimebackIdentity } from '@timeback/sdk'
export const timeback = createTimebackIdentity({
env: 'production',
identity: {
mode: 'sso',
clientId: process.env.AWS_COGNITO_CLIENT_ID!,
clientSecret: process.env.AWS_COGNITO_CLIENT_SECRET!,
onCallbackSuccess: async ({ user, tokens, redirect }) => {
// user is raw OIDC userInfo (sub, email, name, picture, etc.)
// No Timeback profile enrichment in identity-only mode
await createSession({
sub: user.sub,
email: user.email,
name: user.name,
})
return redirect('/')
},
onCallbackError: ({ error, redirect }) => {
return redirect('/login?error=sso_failed')
},
getUser: req => getSessionFromRequest(req),
},
})
Sign-In Flow
The SDK provides aSignInButton component that initiates the SSO flow:
- React
- Vue
- Svelte
- Solid
import { SignInButton } from '@timeback/sdk/react'
function LoginPage() {
return <SignInButton size="lg">Sign in with Timeback</SignInButton>
}
<script setup>
import { SignInButton } from '@timeback/sdk/vue'
</script>
<template>
<SignInButton size="lg">Sign in with Timeback</SignInButton>
</template>
<script>
import { SignInButton } from '@timeback/sdk/svelte'
</script>
<SignInButton size="lg">Sign in with Timeback</SignInButton>
import { SignInButton } from '@timeback/sdk/solid'
function LoginPage() {
return <SignInButton size="lg">Sign in with Timeback</SignInButton>
}
User Verification
Verify if a user has a Timeback account:- React
- Vue
- Svelte
- Solid
import { useTimebackVerification } from '@timeback/sdk/react'
function ProtectedContent() {
const { state } = useTimebackVerification()
if (state.status === 'loading') return <div>Loading...</div>
if (state.status !== 'verified') return <div>Please sign in</div>
return <div>Protected content</div>
}
<script setup>
import { useTimebackVerification } from '@timeback/sdk/vue'
const { state } = useTimebackVerification()
</script>
<template>
<div v-if="state.status === 'loading'">Loading...</div>
<div v-else-if="state.status !== 'verified'">Please sign in</div>
<div v-else>Protected content</div>
</template>
<script>
import { timebackVerification } from '@timeback/sdk/svelte'
</script>
{#if $timebackVerification.status === 'loading'}
<div>Loading...</div>
{:else if $timebackVerification.status !== 'verified'}
<div>Please sign in</div>
{:else}
<div>Protected content</div>
{/if}
import { Show } from 'solid-js'
import { createTimebackVerification } from '@timeback/sdk/solid'
function ProtectedContent() {
const { state } = createTimebackVerification()
return (
<Show when={state.status === 'verified'} fallback={
<Show when={state.status === 'loading'} fallback={<div>Please sign in</div>}>
<div>Loading...</div>
</Show>
}>
<div>Protected content</div>
</Show>
)
}
Next Steps
Custom Activities
Track learning sessions
User Profile
Access user data and XP
Server Adapters
Framework integration
Client Adapters
Client components