Skip to content

User Provisioning Guide

This guide explains how users are automatically provisioned when they connect to your partner application through OAuth, and how this enables seamless SSO authentication.

Overview

When users connect your partner application to Contio via OAuth, the platform handles account creation automatically. This auto-provisioning feature eliminates the need for manual user setup, creating a frictionless onboarding experience for your users.

The User Journey

sequenceDiagram
    participant User
    participant YourApp as "Your Application"
    participant Contio as "Contio"

    User->>YourApp: Click "Connect to Contio"
    YourApp->>Contio: Redirect to OAuth
    Note over Contio: User enters email + OTP
    Note over Contio: Display consent screen
    User->>Contio: Grant permission
    Note over Contio: Account created (if new user)
    Note over Contio: Partner connection established
    Contio->>YourApp: Redirect with authorization code
    YourApp->>Contio: Exchange code for tokens
    Note over YourApp: User is connected!

How Auto-Provisioning Works

When a user completes the OAuth flow with your partner application, Contio automatically:

  1. Creates a new account if the user doesn't already have one
  2. Creates a personal workspace for the user (or adds them to a shared workspace—see below)
  3. Establishes the partner connection linking the user to your application
  4. Returns access tokens for your application to use

This all happens seamlessly during the standard OAuth authorization flow—no additional API calls or setup required.

What Gets Created

Resource Description
User Account Created with the email address from the OAuth flow
Workspace A personal workspace, or the shared workspace specified via workspace_id
Partner Connection Links the user to your partner application, enabling data access

Existing Users

If the user already has a Contio account:

  • No duplicate account is created
  • The partner connection is added to their existing account
  • Access tokens are issued for your application
  • Consent is recorded for your requested scopes

Shared Workspace Provisioning

By default, each new user gets their own personal workspace. If your application needs multiple users to collaborate in the same workspace, you can provision users into a shared workspace by passing workspace_id (and optionally is_admin) in the authentication initiation request.

How It Works

When calling POST /auth/initiate, include the optional workspace_id field to place the user into an existing workspace instead of creating a new one:

{
  "email": "user@example.com",
  "client_id": "partner_abc123",
  "name": "Jane Smith",
  "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
  "is_admin": false
}
Field Type Required Description
workspace_id string (UUID) No ID of an existing workspace to add the user to. Must belong to a user provisioned by your partner app. If omitted, a personal workspace is created.
is_admin boolean No If true, the user is granted WORKSPACE_ADMIN role in the shared workspace. Defaults to false (WORKSPACE_MEMBER).

Validation Rules

The following validations are performed when workspace_id is provided:

Condition HTTP Status Error Code Description
workspace_id is not a valid UUID 400 invalid_request The value must be a valid UUID format
Workspace does not exist 404 workspace_not_found No workspace found with the given ID
Workspace not owned by partner 403 workspace_not_authorized The workspace must belong to a user provisioned by your partner app
User already in a different workspace 409 workspace_conflict The user already belongs to another workspace

Typical Flow

sequenceDiagram
    participant Partner as Your Application
    participant Contio as Contio API

    Note over Partner: First user (workspace creator)
    Partner->>Contio: POST /auth/initiate (no workspace_id)
    Note over Contio: Creates user + personal workspace
    Contio->>Partner: 200 OK

    Note over Partner: Retrieve workspace_id from user profile
    Partner->>Contio: GET /v1/partner/user/profile
    Contio->>Partner: { workspace_id: "ws-123", ... }

    Note over Partner: Subsequent users (shared workspace)
    Partner->>Contio: POST /auth/initiate { workspace_id: "ws-123" }
    Note over Contio: Creates user in existing workspace
    Contio->>Partner: 200 OK

User Profile Response

After provisioning, the user profile endpoint returns workspace details:

{
  "id": "user-uuid",
  "display_name": "Jane Smith",
  "email": "jane@example.com",
  "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
  "workspace_name": "Acme Corp",
  "workspace_role": "WORKSPACE_MEMBER",
  "created_at": "2026-01-15T10:30:00Z"
}

The workspace_role field indicates the user's role: WORKSPACE_OWNER, WORKSPACE_ADMIN, or WORKSPACE_MEMBER.

The Connection Matters

The partner connection created during OAuth is essential—it represents the user's explicit consent for your application to access their Contio data. This connection:

  • Authorizes your application to access the user's meetings, action items, and other data within your requested scopes
  • Enables SSO authentication so users can later sign in via your identity provider (if configured)
  • Persists until revoked by the user or your application

OAuth Before SSO

Users must complete the OAuth flow at least once before they can use SSO. The OAuth flow establishes the partner connection and consent; SSO then uses this existing connection for authentication convenience. SSO alone cannot create new accounts or connections.

Enabling SSO After OAuth

Once users have connected via OAuth, you can offer them a more convenient login experience through Partner IdP SSO. Here's how the two work together:

First-Time User Flow (OAuth Connection)

sequenceDiagram
    participant User
    participant YourApp as "Your Application"
    participant Contio as "Contio"

    User->>YourApp: Click "Connect to Contio"
    YourApp->>Contio: Redirect to OAuth
    Note over Contio: User enters email + OTP
    Note over Contio: Display consent screen
    User->>Contio: Grant permission
    Note over Contio: Account created (if new)
    Note over Contio: Partner connection established
    Contio->>YourApp: Authorization code
    YourApp->>Contio: Exchange for tokens
    Note over YourApp: User is connected!

Returning User Flow (SSO Sign-In)

sequenceDiagram
    participant User
    participant YourApp as "Your Application"
    participant YourIdP as "Your IdP"
    participant Contio as "Contio"

    User->>YourApp: Click "Sign in with SSO"
    YourApp->>Contio: Redirect to /p/{slug}
    Contio->>YourIdP: Redirect to IdP login
    alt User has active IdP session
        Note over YourIdP: Session valid - no prompt
    else No active session
        User->>YourIdP: Enter credentials
    end
    YourIdP->>Contio: Return ID token
    Note over Contio: Validate token
    Note over Contio: Find partner connection ✓
    Contio->>YourApp: User signed in
    Note over YourApp: Session established!

IdP Session Behavior

Your identity provider controls the authentication experience. If the user has an active session with your IdP (e.g., they're already signed into your corporate network), they may be authenticated seamlessly without entering credentials. If no session exists—for example, when accessing via a bookmark, shared link, or after session expiration—your IdP will challenge the user for credentials as configured by your security policies.

Why This Matters

This two-step approach ensures:

  • Explicit consent: Users knowingly authorize your application via the OAuth consent screen
  • Data protection: Your application cannot access user data without prior authorization
  • User control: Users can revoke access at any time
  • Enterprise security: Your IdP handles authentication; Contio handles authorization

Implementation Checklist

To implement user provisioning in your application:

Step 1: Implement OAuth Flow

Follow the OAuth Flow Guide to implement the authorization code flow. When users complete this flow, they are automatically provisioned.

// Redirect users to connect
const authUrl = oauth.getAuthorizationUrl(state, [
  'openid',
  'profile',
  'meetings:read',
  'action-items:read'
]);
res.redirect(authUrl);

Step 2: Store the Connection

After the OAuth callback, store the user's tokens and connection status:

app.get('/callback', async (req, res) => {
  const tokens = await oauth.exchangeCodeForToken(code);

  // Store tokens - user is now provisioned and connected
  await saveUserConnection(userId, {
    accessToken: tokens.access_token,
    refreshToken: tokens.refresh_token,
    expiresAt: Date.now() + (tokens.expires_in * 1000)
  });

  res.redirect('/dashboard');
});

Step 3: (Optional) Configure SSO

If you want to offer SSO as a login option, configure your identity provider following the SSO Integration Guide. Remember: users must complete OAuth first before SSO will work.

Handling Edge Cases

If a user denies the OAuth consent screen, no account or connection is created. Your application receives an error callback:

if (req.query.error === 'access_denied') {
  // User declined - show appropriate message
  res.render('connect-declined');
}

User Already Connected

If a user who is already connected initiates OAuth again:

  • Consent may be skipped if they previously approved the same scopes
  • New tokens are issued (old tokens remain valid until expiry)
  • No duplicate connection is created

Reconnecting After Revocation

If a user or your application revokes the connection, the user can reconnect by completing the OAuth flow again. A new connection is established with fresh consent.

Security Considerations

Auto-provisioning happens during OAuth specifically because the consent screen is shown. This ensures:

  • Users understand what data your application will access
  • Users make an informed decision to connect
  • The connection is auditable and revocable

Partner IdP SSO is designed for authentication convenience, not authorization. Even if you configure SSO:

  • Users without a prior OAuth connection cannot sign in via SSO
  • SSO cannot create new accounts or connections
  • SSO cannot expand the scopes of an existing connection

This separation protects users from unintended data access.

Next Steps