Synchronous User Creation

We currently use Okta to create users within our application. According to the documentation users are activated asynchronously which is problematic for us in our test framework as we often encounter a race condition when we go to log in to a user account that Okta has not finished activating yet. Is there a way we can wait synchronously for a user to be activated? Alternatively, has anyone else had an issue with this and if so how are you currently making sure that a user is fully created and activated before attempting to log in as this user?

bit silly advice, it might be, but you can request user status from Okta to check if itā€™s active or not, maybe?! if it shows the user is active -> go for login

Which test framework are you using?
Depending upon whether the framework supports async/await feature, you can do something like this done in okta node sdk -

Edit: I donā€™t think the await call here waits till user is activated. But I have not seen these tests fail. So adding a bit of a delay after user activation, and polling for user active state could help you.

We actually roll our own test framework in ruby. Itā€™s honestly pretty terrible.
I think weā€™ve tried checking if the user was active upon first login before, but no matter what the status always comes back as null?

Maybe Iā€™ll look in to that a little more.
Just try to log in.
Check user status. (is the user status returned on a failed attempt to log in?)
Wait if they arenā€™t active.
Retry?

EDIT: Maybe itā€™s better to ask. What URL would you recommend checking the users current status against?

/api/v1/users/{{user_id}} should give you all the information about the user, including their status (Get User)

Also, make sure that you create the user with password and activate query parameter set to true.
https://developer.okta.com/docs/reference/api/users/#create-user-with-password

And as @phi1ipp mentioned, you can get the user by ID (https://developer.okta.com/docs/reference/api/users/#get-user-with-id), which should give you the status. If itā€™s ACTIVE, then you should be able to login. You can poll for this with a sleep until the status is returned as ACTIVE before trying to login.

Weā€™re actually using the Java SDK to build our users.
We currently call UserBuilder.instance() with some supplied parameters (including a username and a password and then call.setActive(true) at the end, which Iā€™m hoping is the same as doing this via URL with users?activate=true

Iā€™ve also tried to implement that polling checking if Clients.builder() with our auth parameters and stuff and then calling .build() to build an oktaClient, and then from there checking if oktaClient.getUser(userId).getStatus() == UserStatus.ACTIVE polling up to three times with a 7 second delay between each check.

Do you think this will be sufficient? Is there a guideline for how long we should wait or any information about how long activation usually takes?

I think that should be sufficient. Thereā€™s no guideline on how long the async operations can take. Your polling should work.
Also, I noticed that the java SDK itself has ā€œUser activateā€ test and thereā€™s no polling/wait before we check for an active status.

Technically, this should allow a user to login as well.

So I think as far as activation goes, that part is actually working out now.
The next issue I seem to be encountering is the fact that our users are taking some time to be assigned to our application.

Iā€™ve tried to work around this by waiting upon user creation for this to happen with:

int isUserCurrentlyAssignedCheck = 0;
int maxAssignUserToApplicationChecks = 3;
int sleepTime = 7000;
while (isUserCurrentlyAssignedCheck < maxAssignUserToApplicationChecks) {
    ApplicationList assignedApps
            = oktaClientWrapper.getOktaClient()
                               .http()
                               .get("/api/v1/apps?filter=user.id+eq+\"" + user.getId() + "\"&expand=user/" + user.getId(),
                                    ApplicationList.class);

    Boolean userContainsAssignedApp
            = assignedApps.stream()
                          .map(Application::getName)
                          .anyMatch(applicationName -> applicationName.equalsIgnoreCase(oktaPropertiesService.getCompanyIdentifier()));

    if (userContainsAssignedApp) {
        break;
    } else {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException interruptedException) {
            throw new AppException("Error trying to wait for Okta to provision user", interruptedException);
        }
    }

    isUserCurrentlyAssignedCheck++;
}

if (isUserCurrentlyAssignedCheck >= maxAssignUserToApplicationChecks) {
    throw new OktaException("Timed out waiting for Okta to assign user to application after "
                                    + sleepTime * isUserCurrentlyAssignedCheck
                                    + " milliseconds");
}

// continue doing user stuff

My hope is that this will work out.

Iā€™m reading through the user provisioning documentation right now and it actually mentions users having an externalId after being completely provisioned? It seems like maybe it would be better to check for this externalId instead of looking through the list of assigned applications, but the SDK doesnā€™t seem to expose this externalId.

Any advice or recommendations on this front?
Also, thank you so much for all the help so far!

1 Like

Iā€™ve been digging in to this more, and Iā€™m still having issues.

I tried checking for an externalId upon user creation and it seems like no matter what this is always null in the embedded data when I fetch the users applications. Iā€™ve sat there polling for at least a minute on user creation which creates a super crappy user experience, and it never gets set.

I ended up reading more about provisioning and saw that

Users in Okta are linked to a user in a target application via an externalId . Okta anchors a user with his or her externalId during an import or provisioning synchronization event. Okta uses the native app-specific identifier or primary key for the user as the externalId . The externalId is selected during import when the user is confirmed (reconciled) or during provisioning when the user has been successfully created in the target application.

When the background provisioning job completes successfully, the application user transitions to the PROVISIONED status.

  • Application user is assigned an externalId when successfully provisioned in the target application. The externalId should be immutable for the life of the assignment.

This lead me to believe I could wait for an externalId, but it never seems to come. Is there something I can/have to do to manually kick off provisioning for this user?

I also noticed that:

SSO Application Assignments (for example, SAML or SWA) donā€™t have an externalId as they arenā€™t synchronized with the application.

This doesnā€™t seem to fit our case according to who Iā€™ve asked, but:

Single Sign-On
Users assigned to an application for SSO without provisioning features enabled have an ACTIVE status with syncState as DISABLED .

Lead me to believe that maybe checking that if our status was ACTIVE and our syncState was DISABLED this might be enough, but I still end up getting

2020-06-05 06:18:33,905 [Thread-22] ERROR com.company.web.CallbackController- An error has occurred while attempting to authenticate the user
org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden

I was actually getting 400ā€™s before but now Iā€™m getting outright 403ā€™s which is odd? This also doesnā€™t happen all the timeā€¦ Only on what seems to be a rare occasion when Iā€™m neck deep in creating butt loads of users for testing.

1 Like