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!
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 herexternalId
during an import or provisioning synchronization event. Okta uses the native app-specific identifier or primary key for the user as theexternalId
. TheexternalId
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. TheexternalId
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 anACTIVE
status withsyncState
asDISABLED
.
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.