Skip to content

feat: staged account creation and profile attribute support#145

Open
c1-dev-bot[bot] wants to merge 3 commits into
mainfrom
ce-519/staged-account-creation-and-profile-attributes
Open

feat: staged account creation and profile attribute support#145
c1-dev-bot[bot] wants to merge 3 commits into
mainfrom
ce-519/staged-account-creation-and-profile-attributes

Conversation

@c1-dev-bot
Copy link
Copy Markdown
Contributor

@c1-dev-bot c1-dev-bot Bot commented Mar 11, 2026

Summary

  • Add create_in_staged_status field to account creation schema, allowing users to be created in Okta's STAGED status instead of being immediately activated. Staged users can be activated later via Okta workflows or API calls.
  • Add support for populating common Okta profile attributes during account creation: department, title, display_name, user_type, organization, manager_id, cost_center, division, and employee_number.
  • Refactor boolean field parsing into a shared parseBoolField helper for cleaner code.

Details

Staged Account Creation

When create_in_staged_status is set to true, the Okta CreateUser API is called with activate=false, which creates the user in STAGED status. This is useful for onboarding workflows where user activation is controlled by separate Okta workflows or happens at a scheduled time.

Profile Attributes

The following optional Okta profile attributes can now be set during account creation:

Schema Field Okta Profile Attribute
department department
title title
display_name displayName
user_type userType
organization organization
manager_id managerId
cost_center costCenter
division division
employee_number employeeNumber

Test Plan

  • go build ./... passes
  • go test ./... passes
  • Manual testing: create user with create_in_staged_status=true and verify STAGED status in Okta
  • Manual testing: create user with profile attributes and verify they appear in Okta profile
  • Manual testing: create user without new fields to verify backward compatibility

Fixes: CE-519


Automated PR Notice

This PR was automatically created by c1-dev-bot as a potential implementation.

This code requires:

  • Human review of the implementation approach
  • Manual testing to verify correctness
  • Approval from the appropriate team before merging

Add support for creating Okta users in STAGED status (not immediately
activated) via a new `create_in_staged_status` field in the account
creation schema. Staged users can be activated later through Okta
workflows or API calls.

Also add support for populating common Okta profile attributes during
account creation: department, title, display_name, user_type,
organization, manager_id, cost_center, division, and employee_number.

Fixes: CE-519
@c1-dev-bot c1-dev-bot Bot requested a review from a team March 11, 2026 04:55
@linear
Copy link
Copy Markdown

linear Bot commented Mar 11, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 11, 2026

Claude finished @c1-dev-bot[bot]'s task in 1m 25s —— View job


PR Review: Staged Account Creation & Profile Attributes

  • Read changed files and PR diff
  • Review implementation for correctness and best practices
  • Post review feedback

Overall Assessment

This is a well-structured PR that adds two useful features cleanly. The parseBoolField refactor is a good improvement, and the optionalProfileFields map pattern keeps the profile population logic DRY. I have a few observations ranging from a potential behavioral concern to minor suggestions.

Issues

1. Staged creation bypasses credential handling — is this intentional?

pkg/connector/user.go:623-629 — When create_in_staged_status is true, getAccountCreationQueryParams returns early with Activate: false, skipping the credentialOptions.GetNoPassword() check and the password_change_on_login_required logic entirely. This means:

  • Even if credentials were provided, the nextLogin=changePassword param won't be set
  • The user will still get credentials set on the CreateUserRequest (via getCredentialOption), but the activation params are ignored

This is likely fine for staged users (they aren't activated yet, so login params don't apply), but it should be explicitly documented in the code comment or the schema description, since someone might set both create_in_staged_status=true and password_change_on_login_required=true expecting both to take effect.

Suggestion: Add a note to the create_in_staged_status schema description, e.g., "Note: When staged, password change on login settings are deferred until activation."

2. create_in_staged_status is a boolean field defined as a string schema

pkg/connector/connector.go:328-336 — The create_in_staged_status field (and the existing password_change_on_login_required) use StringField type with placeholder "True/False". While parseBoolField handles both string and bool types at runtime, this is a minor schema mismatch — ideally these would use a BoolField type if available in the SDK. If BoolField is not available, this is fine as-is and consistent with existing patterns.

3. Map iteration order is non-deterministic (minor, non-issue)

pkg/connector/user.go:586-592 — Iterating over optionalProfileFields has non-deterministic order in Go, but since each key maps to a unique profile field and we're just setting values on a map, this is perfectly fine. Just noting for completeness.

Positive Aspects

  • parseBoolField helper (user.go:597-613) — Good refactor. Handles bool, string, and nil types with a clear default error case. This is reused for both create_in_staged_status and password_change_on_login_required, removing duplication.

  • optionalProfileFields map (user.go:544-555) — Clean, declarative approach to mapping schema fields to Okta profile attributes. Easy to extend with new fields in the future.

  • Schema definitions — Well-ordered, clear descriptions, and consistent with existing field patterns.

Minor Suggestions

  1. Consider whether the parseBoolField error message prefix should use "baton-okta" instead of "okta-connectorv2" for consistency with the CLAUDE.md guidance (baton-service pattern). I see the codebase already uses "okta-connectorv2" throughout, so this is consistent with existing code — just flagging for awareness.

  2. The (*profile)[oktaField] = strVal dereference at user.go:589 could be simplified to profile[oktaField] = strVal since okta.UserProfile is likely a map type and the pointer dereference is unnecessary when indexing.

Simplify profile map access →

Summary

The PR is solid and ready for merge after considering the behavioral note about staged creation bypassing credential params (issue #1). The code is clean, well-organized, and follows existing patterns. No blocking issues found.


@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 11, 2026

Claude finished @c1-dev-bot[bot]'s task in 2m 0s —— View job


PR Review: Staged Account Creation & Profile Attributes

  • Read changed files and PR diff
  • Review implementation for correctness and best practices
  • Post review feedback

Blocking Issues: 0 | Suggestions: 2

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  1. Simplify map dereferencepkg/connector/user.go:589: (*profile)[oktaField] can be simplified to profile[oktaField] since okta.UserProfile is a map type and the pointer dereference is unnecessary when indexing.

  2. Behavioral change in parseBoolFieldpkg/connector/user.go:597-613: The new parseBoolField helper adds a default error case for unexpected types, whereas the old inline switch silently treated them as false. This is an improvement but worth noting as a minor behavioral change.

Notes

  • The previous automated review (from the initial commit) raised valid points about staged creation bypassing credential params and the string-typed boolean fields. Those observations still apply and are not re-raised here.
  • No documentation staleness detected — docs/connector.mdx does not enumerate account creation schema fields, so the new fields don't create a stale-docs situation.
  • No breaking changes — all additions are backward-compatible optional fields.

Overall this is a clean, well-structured PR. The parseBoolField refactor and optionalProfileFields map pattern are good improvements.


Comment thread pkg/connector/user.go
for schemaField, oktaField := range optionalProfileFields {
if val, ok := pMap[schemaField]; ok {
if strVal, isStr := val.(string); isStr && strVal != "" {
(*profile)[oktaField] = strVal
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: okta.UserProfile is a map type (map[string]interface{}), so the pointer dereference is unnecessary when indexing. You can simplify this to profile[oktaField] = strVal.

Suggested change
(*profile)[oktaField] = strVal
profile[oktaField] = strVal

Comment thread pkg/connector/user.go
Comment on lines +597 to +613
func parseBoolField(pMap map[string]interface{}, fieldName string) (bool, error) {
val := pMap[fieldName]
switch v := val.(type) {
case bool:
requirePasswordChanged = v
return v, nil
case string:
parsed, err := strconv.ParseBool(v)
if err != nil {
return nil, err
return false, err
}
requirePasswordChanged = parsed
return parsed, nil
case nil:
// Do nothing
return false, nil
default:
return false, fmt.Errorf("okta-connectorv2: unsupported type for %s: %T", fieldName, val)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: The parseBoolField refactor adds a default error case that didn't exist in the original inline switch (which silently treated unexpected types as false). This is a good improvement — explicitly erroring on unexpected types is safer than silent fallthrough. Just noting this is a minor behavioral change from the previous code.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 11, 2026

Claude finished @c1-dev-bot[bot]'s task in 1m 31s —— View job


PR Review: Staged Account Creation & Profile Attributes

  • Read changed files and PR diff
  • Review implementation for correctness and best practices
  • Post review feedback

Blocking Issues: 0 | Non-blocking: 3

Correctness

The implementation is clean and correct. Both features (staged creation and optional profile attributes) are well-structured and backward-compatible. No security or correctness issues found.

Findings

1. Previous review suggestion to simplify (*profile)[oktaField] is incorrect

pkg/connector/user.go:589 — A previous automated review suggested changing (*profile)[oktaField] to profile[oktaField]. This would not compile. Since okta.UserProfile is map[string]interface{} (v2 SDK), and profile is *okta.UserProfile (i.e., *map[string]interface{}), Go does not auto-dereference pointers for map indexing — the explicit (*profile) is required.

A cleaner alternative would be to avoid the pointer in the first place:

profile := okta.UserProfile{
    "firstName": firstName,
    "lastName":  lastName,
    "email":     email,
    "login":     login,
}
// then: profile[oktaField] = strVal
// and: return &profile, nil

This is purely a style preference and not blocking.

Simplify by avoiding pointer →

2. Staged creation bypasses credential parameters — worth documenting

pkg/connector/user.go:623-629 — When create_in_staged_status is true, getAccountCreationQueryParams returns early, skipping the password_change_on_login_required logic. This is correct behavior (staged users aren't activated, so login params don't apply), but someone might set both flags expecting both to take effect. The inline comment at line 623-624 is good but consider also noting this in the schema description for create_in_staged_status in connector.go:331:

"When 'true', the user is created in STAGED status instead of being activated.
Staged users can be activated later via Okta workflows.
Note: password_change_on_login_required is ignored when this is set."

3. parseBoolField is a good refactor with a minor behavioral change

pkg/connector/user.go:597-613 — The new parseBoolField helper adds a default error case for unexpected types, where the old inline switch silently treated them as false. This is an improvement — explicitly erroring on unexpected types is safer. Just noting this is an intentional behavioral change.

Positive Aspects

  • optionalProfileFields map (line 545-555) — Clean, declarative approach. Easy to extend with new fields.
  • parseBoolField helper — Good DRY refactor, handles bool, string, and nil types properly.
  • Schema definitions — Well-ordered, clear descriptions, consistent with existing patterns.
  • Backward compatibility — All additions are optional fields with sensible defaults.

Summary

This is a solid, well-structured PR. No blocking issues. The code is clean, follows existing patterns, and both features are implemented correctly. Ready for merge after considering the minor documentation suggestion.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants