Migrate to Full Stack Authentication
Migrating authentication is a big job. But moving to Scalekit pays dividends: you off-load SSO integrations, SCIM provisioning, session handling, and more—so your team can focus on product. This guide walks you through a safe, incremental migration from any existing solution to Scalekit’s full-stack auth platform.
This migration guide helps you:
- Export user and organization data from your current system
- Import data into Scalekit using APIs or SDKs
- Update your application’s authentication flows
- Test and deploy the new authentication system
-
Audit and export your data
Section titled “Audit and export your data”Before you switch to Scalekit, create a comprehensive inventory of your existing setup and export your data:
Code audit:
- Sign-up and login flows
- Session middleware and token validation
- Role-based access control (RBAC) logic
- Email verification flows
- Logout and session termination
Data export:
- User records (emails, names, verification status)
- Organization/tenant structure
- Role assignments and permissions
- Authentication provider configurations (if using SSO)
Backup plan:
- Export a sample JWT token or session cookie to understand your current format
- Set up a feature flag to route traffic back to the old system if needed
- Document your rollback procedure
The minimal user schema looks like this:
Field Description Status email
Primary login identifier. Required first_name
The user’s given name. Optional last_name
The user’s family name. Optional email_verified
Boolean flag. Treated as false
if omitted.Optional -
Import organizations and users
Section titled “Import organizations and users”Transform your exported data to match Scalekit’s format. The
external_id
field is crucial—it stores your original primary key, enabling seamless lookups between your system and Scalekit.npm install @scalekit-sdk/nodepip install scalekit-sdk-pythongo get -u github.com/scalekit-inc/scalekit-sdk-go/* Gradle users - add the following to your dependencies in build file */implementation "com.scalekit:scalekit-sdk-java:1.1.3"<!-- Maven users - add the following to your `pom.xml` --><dependency><groupId>com.scalekit</groupId><artifactId>scalekit-sdk-java</artifactId><version>1.1.3</version></dependency>Create organizations first:
Create an organization curl "$SCALEKIT_ENVIRONMENT_URL/api/v1/organizations" \--request POST \--header 'Content-Type: application/json' \--data '{"display_name": "Megasoft Inc","external_id": "org_123","metadata": { "plan": "enterprise" }}'Create organizations const organizations = [{ display_name: "Megasoft Inc", external_id: "org_123", metadata: { plan: "enterprise" } },{ display_name: "Acme Corp", external_id: "org_456", metadata: { plan: "starter" } }];for (const org of organizations) {const result = await scalekit.organization.createOrganization(org.display_name,{externalId: org.external_id,metadata: org.metadata});console.log(`Created organization: ${result.id}`);}Create organizations from scalekit.v1.organizations.organizations_pb2 import CreateOrganizationorganizations = [{"display_name": "Megasoft Inc", "external_id": "org_123", "metadata": {"plan": "enterprise"}},{"display_name": "Acme Corp", "external_id": "org_456", "metadata": {"plan": "starter"}}]for org in organizations:result = scalekit_client.organization.create_organization(CreateOrganization(display_name=org["display_name"],external_id=org["external_id"],metadata=org["metadata"]))print(f"Created organization: {result.id}")Create organizations organizations := []struct {DisplayName stringExternalID stringMetadata map[string]interface{}}{{"Megasoft Inc", "org_123", map[string]interface{}{"plan": "enterprise"}},{"Acme Corp", "org_456", map[string]interface{}{"plan": "starter"}},}for _, org := range organizations {result, err := scalekit.Organization.CreateOrganization(ctx,org.DisplayName,scalekit.CreateOrganizationOptions{ExternalID: org.ExternalID,Metadata: org.Metadata,},)if err != nil {log.Fatal(err)}fmt.Printf("Created organization: %s\n", result.ID)}Create organizations List<Map<String, Object>> organizations = Arrays.asList(Map.of("display_name", "Megasoft Inc", "external_id", "org_123", "metadata", Map.of("plan", "enterprise")),Map.of("display_name", "Acme Corp", "external_id", "org_456", "metadata", Map.of("plan", "starter")));for (Map<String, Object> org : organizations) {CreateOrganization createOrganization = CreateOrganization.newBuilder().setDisplayName((String) org.get("display_name")).setExternalId((String) org.get("external_id")).putAllMetadata((Map<String, String>) org.get("metadata")).build();Organization result = scalekitClient.organizations().create(createOrganization);System.out.println("Created organization: " + result.getId());}Then create users within organizations:
Create a user inside an organization curl "$SCALEKIT_ENVIRONMENT_URL/api/v1/organizations/{organization_id}/users" \--request POST \--header 'Content-Type: application/json' \--data '{"email": "user@example.com","external_id": "usr_987","membership": {"roles": ["admin"],"metadata": { "department": "engineering" }},"user_profile": {"first_name": "John","last_name": "Doe","locale": "en-US"}}'Create users in organizations const { user } = await scalekit.user.createUserAndMembership("org_123", {email: "user@example.com",externalId: "usr_987",metadata: {department: "engineering",location: "nyc-office"},userProfile: {firstName: "John",lastName: "Doe",},});Create users in organizations from scalekit.v1.users.users_pb2 import CreateUserfrom scalekit.v1.commons.commons_pb2 import UserProfileuser_msg = CreateUser(email="user@example.com",external_id="usr_987",metadata={"department": "engineering", "location": "nyc-office"},user_profile=UserProfile(first_name="John",last_name="Doe"))create_resp, _ = scalekit_client.user.create_user_and_membership("org_123", user_msg)Create users in organizations newUser := &usersv1.CreateUser{Email: "user@example.com",ExternalId: "usr_987",Metadata: map[string]string{"department": "engineering","location": "nyc-office",},UserProfile: &usersv1.CreateUserProfile{FirstName: "John",LastName: "Doe",},}cuResp, err := scalekit.User().CreateUserAndMembership(ctx, "org_123", newUser, false)if err != nil {log.Fatal(err)}Create users in organizations CreateUser createUser = CreateUser.newBuilder().setEmail("user@example.com").setExternalId("usr_987").putMetadata("department", "engineering").putMetadata("location", "nyc-office").setUserProfile(CreateUserProfile.newBuilder().setFirstName("John").setLastName("Doe").build()).build();CreateUserAndMembershipResponse cuResp = scalekitClient.users().createUserAndMembership("org_123", createUser);System.out.println("Created user: " + cuResp.getUser().getId());- Batch your imports—run them in parallel for speed but respect rate limits
- Include
"sendInvitationEmail": false
when creating users to skip invite emails. Scalekit will automatically set the membership status toactive
and mark the email as verified.
-
Configure redirects and roles
Section titled “Configure redirects and roles”The authentication callback URL is necessary for tokens to return safely. However, depending on your application, you may want to add more redirects (such as post-logout URLs, so you can control the user experience and destination after logout). Head to Settings → Redirects in the dashboard. Review our redirect URI guide for validation rules and wildcard configuration.
Set up roles: Define roles in Scalekit to control what actions users can perform in your application. When users log in, Scalekit provides their assigned roles to your application.
- Create your roles under User Management → Roles or via the SDK
- While importing users, include the
roles
array in themembership
object. Read more about roles. - Need organization-specific roles? Reach out to discuss your requirements
-
Update your application code
Section titled “Update your application code”Replace session middleware: Replace legacy JWT validation with the Scalekit SDK or our JWKS endpoint. Verify:
- Access tokens are accepted across all routes
- Refresh tokens renew seamlessly
- Ensure your application’s checks use the
roles
claim from Scalekit’s tokens (learn more)
Customize your Login Page: Your application redirects users to a Scalekit-hosted login page. Tailor the experience by updating your logo, colours, copy, and legal links in the dashboard.
Update secondary flows:
- Verify email prompt
- Branding (logo, colours, legal copy)
-
Deploy and monitor
Section titled “Deploy and monitor”Execute your migration carefully with proper monitoring:
Pre-deployment testing:
- Test login flows with a few migrated users
- Verify session management and token validation
- Check role-based access control
Deployment steps:
- Deploy your updated application code
- Enable the feature flag to route traffic to Scalekit
- Monitor authentication success rates and error logs
- Have your rollback plan ready
Post-deployment monitoring:
- Watch authentication error rates
- Monitor session creation and validation
- Check user feedback and support tickets
- Verify SSO connections work correctly
Frequently Asked Questions
Section titled “Frequently Asked Questions”Why can’t users log in after migration?
- Verify callback URLs are registered in Scalekit dashboard
- Check that
external_id
mappings are correct - Ensure email addresses match exactly between systems
Why is session validation failing?
- Update JWT validation to use Scalekit’s JWKS endpoint
- Verify token expiration and refresh logic
- Check that role claims are read correctly
Why aren’t SSO connections working?
- Confirm organization has SSO enabled in features
- Verify identity provider configuration
- Test with IdP-initiated login