Identity & SSO
Custom OAuth2 / OIDC identity provider serving all ICC products and third-party apps.

ICC Business SSO

A custom OAuth2 / OpenID Connect server built on django-oauth-toolkit. Chosen over Auth0/Okta because cannabis license number and type must be first-class identity attributes — not custom claims bolted onto a generic JWT. Cross-subdomain SSO works because all products share the .intelcann.app root domain.

Business identity model

  • User (email-based, no username required)
  • BusinessProfile (legal name, EIN, address)
  • BusinessLicense (number, type, state, expiry)
  • BusinessMember (user ↔ business + role + per-product access)

Roles & permissions

RoleDefault access
AdminAll products + team management + MFA required
ManagerAll enabled products, no team management
StaffRead-only; explicit product override required

JWT Token Payload

Scopes: read write ccx maps bmc  ·  Access token: 15 min  ·  Refresh token: 30 days (rotated on use)

{
  "sub": "uuid-of-user",
  "email": "user@company.com",
  "email_verified": true,
  "business_id": "uuid-of-business",
  "business_name": "Acme Farms LLC",
  "role": "admin",
  "permitted_products": ["ccx", "maps", "bmc"],
  "license_types": ["cultivator", "distributor"],
  "iss": "https://id.intelcann.app",
  "aud": "ccx-client-id"
}

MFA Strategy

MethodWhoCostSecurity
TOTP authenticator app
Google/Microsoft Authenticator
Admin + Manager roles (required) ~$0 (pyotp library) Highest
Email OTP Staff + fallback for all roles ~$0.0001/email Medium
SMS OTP ICC Social consumers (optional) ~$0.008–$0.01/SMS Lower (SIM swap risk)

COSINT — ICC as Third-Party Identity Provider

COSINT is a separate ICC-owned app. Users can sign in with ICC credentials alongside Google and native auth. ICC acts as the OIDC provider; COSINT has its own subscription-tier permission model.

How it works

1
User clicks "Sign in with ICC"
Redirected to id.intelcann.app with client_id and PKCE code_challenge
2
User authenticates on ICC login page
Email + password + MFA. Consent screen: "Allow COSINT access?"
3
Redirect back to COSINT with auth code
Code exchange happens server-to-server (never in browser)
4
COSINT receives ID token
Looks up user by icc_sub (permanent UUID). Creates or links account. Applies COSINT subscription tier.

ID token sent to COSINT

{
  "sub": "icc-user-uuid",
  "email": "user@example.com",
  "email_verified": true,
  "account_type": "business",
  "given_name": "...",
  "iss": "https://id.intelcann.app",
  "aud": "cosint-client-id"
}

ICC never sees COSINT's subscription tiers. COSINT never manages passwords for ICC users.


CDAP — License Verification Integration

CDAP is a separate ICC-owned app that verifies cannabis licenses against state regulatory databases. ICC queries CDAP during business onboarding to supplement manual admin review.

Verification workflow

1
Business submits license on CCX or BMC
License number, type, and issuing state submitted
2
ICC queries CDAP API
Triggered automatically on BusinessLicense creation
3
CDAP returns verification result
Status, license type confirmation, expiry date, any flags (suspended, expired)
4
Admin reviews and confirms
CDAP result supplements — does not replace — human review. Admin clicks "Verify" in Django admin to activate the business account.