diff --git a/.gitignore b/.gitignore index c0a93e5c..3047885f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # Ignore IntelliJ projects .idea +.settings/org.eclipse.jdt.core.prefs # Ignore Eclipse projects .project diff --git a/README.md b/README.md index 41933112..f5a17d72 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ WorkOS workos = new WorkOS("WORKOS_API_KEY"); // workos.passwordless // workos.portal // workos.sso +// workos.userManagement // workos.webhooks ``` @@ -62,9 +63,23 @@ For our SDKs WorkOS follows a Semantic Versioning ([SemVer](https://semver.org/) See full examples at https://github.com/workos-inc/java-example-applications. +## Beta Releases + +WorkOS has features in Beta that can be accessed via Beta releases. We would love for you to try these +and share feedback with us before these features reach general availability (GA). To install a Beta version, +please follow the [installation steps](#installation) above using the Beta release version. + +> Note: there can be breaking changes between Beta versions. Therefore, we recommend pinning the package version to a +> specific version. This way you can install the same version each time without breaking changes unless you are +> intentionally looking for the latest Beta version. + +We highly recommend keeping an eye on when the Beta feature you are interested in goes from Beta to stable so that you +can move to using the stable version. + ## More Information - [Single Sign-On Guide](https://workos.com/docs/sso/guide) - [Directory Sync Guide](https://workos.com/docs/directory-sync/guide) +- [User Management](https://workos.com/docs/user-management/guide) - [Admin Portal Guide](https://workos.com/docs/admin-portal/guide) - [Magic Link Guide](https://workos.com/docs/magic-link/guide) diff --git a/src/main/kotlin/com/workos/WorkOS.kt b/src/main/kotlin/com/workos/WorkOS.kt index 29ca1321..94a71aad 100644 --- a/src/main/kotlin/com/workos/WorkOS.kt +++ b/src/main/kotlin/com/workos/WorkOS.kt @@ -21,6 +21,7 @@ import com.workos.organizations.OrganizationsApi import com.workos.passwordless.PasswordlessApi import com.workos.portal.PortalApi import com.workos.sso.SsoApi +import com.workos.usermanagement.UserManagementApi import com.workos.webhooks.WebhooksApi import org.apache.http.client.utils.URIBuilder import java.lang.IllegalArgumentException @@ -95,6 +96,12 @@ class WorkOS( @JvmField val mfa = MfaApi(this) + /** + * Module for interacting with the User Management API. + */ + @JvmField + val userManagement = UserManagementApi(this) + /** * Module for interacting with the Webhooks API. */ @@ -255,17 +262,21 @@ class WorkOS( val responseData = mapper.readValue(payload, BadRequestExceptionResponse::class.java) throw BadRequestException(responseData.message, responseData.code, responseData.errors, requestId) } + 401 -> { val responseData = mapper.readValue(payload, GenericErrorResponse::class.java) throw UnauthorizedException(responseData.message, requestId) } + 404 -> { throw NotFoundException(response.url.path, requestId) } + 422 -> { val unprocessableEntityException = mapper.readValue(payload, UnprocessableEntityExceptionResponse::class.java) throw UnprocessableEntityException(unprocessableEntityException.message, unprocessableEntityException.code, unprocessableEntityException.errors, requestId) } + else -> { val responseData = mapper.readValue(payload, GenericErrorResponse::class.java) throw GenericServerException(responseData.message, status, requestId) diff --git a/src/main/kotlin/com/workos/usermanagement/UserManagementApi.kt b/src/main/kotlin/com/workos/usermanagement/UserManagementApi.kt new file mode 100644 index 00000000..aa70418c --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/UserManagementApi.kt @@ -0,0 +1,377 @@ +package com.workos.usermanagement + +import com.workos.WorkOS +import com.workos.common.http.RequestConfig +import com.workos.usermanagement.builders.AuthenticationWithCodeOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithEmailVerificationOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithMagicAuthOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithOrganizationSelectionOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithPasswordOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithRefreshTokenOptionsBuilder +import com.workos.usermanagement.builders.AuthenticationWithTotpOptionsBuilder +import com.workos.usermanagement.builders.AuthorizationUrlOptionsBuilder +import com.workos.usermanagement.builders.ResetPasswordOptionsBuilder +import com.workos.usermanagement.builders.SendMagicAuthCodeOptionsBuilder +import com.workos.usermanagement.builders.SendPasswordResetEmailOptionsBuilder +import com.workos.usermanagement.builders.UpdateOrganizationMembershipOptionsBuilder +import com.workos.usermanagement.models.Authentication +import com.workos.usermanagement.models.AuthenticationFactors +import com.workos.usermanagement.models.EnrolledAuthenticationFactor +import com.workos.usermanagement.models.Identity +import com.workos.usermanagement.models.Invitation +import com.workos.usermanagement.models.Invitations +import com.workos.usermanagement.models.OrganizationMembership +import com.workos.usermanagement.models.OrganizationMemberships +import com.workos.usermanagement.models.RefreshAuthentication +import com.workos.usermanagement.models.User +import com.workos.usermanagement.models.Users +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.CreateOrganizationMembershipOptions +import com.workos.usermanagement.types.CreateUserOptions +import com.workos.usermanagement.types.EnrolledAuthenticationFactorOptions +import com.workos.usermanagement.types.ListInvitationsOptions +import com.workos.usermanagement.types.ListOrganizationMembershipsOptions +import com.workos.usermanagement.types.ListUsersOptions +import com.workos.usermanagement.types.SendInvitationOptions +import com.workos.usermanagement.types.UpdateUserOptions +import org.apache.http.client.utils.URIBuilder + +class UserManagementApi(private val workos: WorkOS) { + /** + * Get the details of an existing user. + */ + fun getUser(userId: String): User { + return workos.get("/user_management/users/$userId", User::class.java) + } + + /** + * Get a list of all the existing users matching the criteria specified. + */ + fun listUsers(options: ListUsersOptions? = null): Users { + return workos.get( + "/user_management/users", + Users::class.java, + RequestConfig.builder().data(options ?: ListUsersOptions()).build() + ) + } + + /** + * Create a new user in the current environment. + */ + fun createUser(options: CreateUserOptions): User { + return workos.post( + "/user_management/users", + User::class.java, + RequestConfig.builder().data(options).build() + ) + } + + /** + * Updates properties of a user. The omitted properties will be left unchanged. + */ + fun updateUser(userId: String, options: UpdateUserOptions): User { + return workos.put( + "/user_management/users/$userId", + User::class.java, + RequestConfig.builder().data(options).build() + ) + } + + /** + * Deletes a user in the current environment. + */ + fun deleteUser(userId: String) { + workos.delete("/user_management/users/$userId") + } + + /** + * Get the identities associated with the user. + */ + fun getUserIdentities(userId: String): Array { + return workos.get("/user_management/users/$userId/identities", Array::class.java) + } + + /** + * Generate an Oauth2 authorization URL where users will + * authenticate using the configured SSO Identity Provider. + */ + fun getAuthorizationUrl(clientId: String, redirectUri: String): AuthorizationUrlOptionsBuilder { + return AuthorizationUrlOptionsBuilder.create(workos.baseUrl, clientId, redirectUri) + } + + /** + * Authenticates a user using AuthKit, OAuth or an organization’s SSO connection. + */ + fun authenticateWithCode(clientId: String, code: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithCodeOptionsBuilder.create( + clientId, workos.apiKey, code, options + ).build() + ).build() + ) + } + + /** + * Authenticates a user with email and password. + */ + fun authenticateWithPassword(clientId: String, email: String, password: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithPasswordOptionsBuilder.create( + clientId, workos.apiKey, email, password, options + ).build() + ).build() + ) + } + + /** + * Authenticates a user by verifying the Magic Auth code sent to the user’s email. + */ + fun authenticateWithMagicAuth(clientId: String, email: String, code: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithMagicAuthOptionsBuilder.create( + clientId, workos.apiKey, email, code, options + ).build() + ).build() + ) + } + + /** + * Use this endpoint to exchange a refresh token for a new access token. Refresh tokens are single use, so a new refresh token is returned. + */ + fun authenticateWithRefreshToken(clientId: String, refreshToken: String, options: AuthenticationAdditionalOptions? = null): RefreshAuthentication { + return workos.post( + "/user_management/authenticate", + RefreshAuthentication::class.java, + RequestConfig.builder().data( + AuthenticationWithRefreshTokenOptionsBuilder.create( + clientId, workos.apiKey, refreshToken, options + ).build() + ).build() + ) + } + + /** + * Authenticates a user with an unverified email and verifies their email address. + */ + fun authenticateWithEmailVerification(clientId: String, code: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithEmailVerificationOptionsBuilder.create( + clientId, workos.apiKey, code, pendingAuthenticationToken, options + ).build() + ).build() + ) + } + + /** + * Authenticates a user enrolled into MFA using time-based one-time password (TOTP). + */ + fun authenticateWithTotp(clientId: String, code: String, authenticationChallengeId: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithTotpOptionsBuilder.create( + clientId, workos.apiKey, code, authenticationChallengeId, pendingAuthenticationToken, options + ).build() + ).build() + ) + } + + /** + * Authenticates a user into an organization they are a member of. + */ + fun authenticateWithOrganizationSelection(clientId: String, organizationId: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): Authentication { + return workos.post( + "/user_management/authenticate", + Authentication::class.java, + RequestConfig.builder().data( + AuthenticationWithOrganizationSelectionOptionsBuilder.create( + clientId, workos.apiKey, organizationId, pendingAuthenticationToken, options + ).build() + ).build() + ) + } + + /** + * This hosts the public key that is used for verifying access tokens. + */ + fun getJwksUrl(clientId: String): String { + return URIBuilder(workos.baseUrl) + .setPath("/sso/jwks/$clientId") + .toString() + } + + /** + * Sends a one-time authentication code to the user’s email address. The code + * expires in 10 minutes. To verify the code, authenticate the user with Magic Auth. + */ + fun sendMagicAuthCode(email: String) { + workos.post( + "/user_management/magic_auth/send", + RequestConfig.builder().data( + SendMagicAuthCodeOptionsBuilder.create( + email + ).build() + ).build() + ) + } + + /** + * Enrolls a user in a new authentication factor. + */ + fun enrollAuthFactor(id: String, options: EnrolledAuthenticationFactorOptions? = null): EnrolledAuthenticationFactor { + return workos.post( + "/user_management/users/$id/auth_factors", + EnrolledAuthenticationFactor::class.java, + RequestConfig.builder().data(options ?: EnrolledAuthenticationFactorOptions()).build() + ) + } + + /** + * Get a list of all authentication factors of a given user. + */ + fun listAuthFactors(id: String): AuthenticationFactors { + return workos.get( + "/user_management/users/$id/auth_factors", + AuthenticationFactors::class.java, + ) + } + + /** + * Send a password reset email and change the user’s password. + */ + fun sendPasswordResetEmail(email: String, passwordResetUrl: String) { + return workos.post( + "/user_management/password_reset/send", + RequestConfig.builder().data( + SendPasswordResetEmailOptionsBuilder.create( + email, passwordResetUrl + ).build() + ).build() + ) + } + + /** + * Sets a new password using the `token` query parameter from the link that the user received. + */ + fun resetPassword(token: String, newPassword: String): User { + return workos.post( + "/user_management/password_reset/confirm", + User::class.java, + RequestConfig.builder().data( + ResetPasswordOptionsBuilder.create( + token, newPassword + ).build() + ).build() + ) + } + + /** + * Get the details of an existing organization membership. + */ + fun getOrganizationMembership(id: String): OrganizationMembership { + return workos.get("/user_management/organization_memberships/$id", OrganizationMembership::class.java) + } + + /** + * Get a list of all organization memberships matching the criteria specified. + */ + fun listOrganizationMemberships(options: ListOrganizationMembershipsOptions? = null): OrganizationMemberships { + return workos.get( + "/user_management/organization_memberships", + OrganizationMemberships::class.java, + RequestConfig.builder().data(options ?: ListOrganizationMembershipsOptions()).build() + ) + } + + /** + * Creates a new organization membership for the given organization and user. + */ + fun createOrganizationMembership(options: CreateOrganizationMembershipOptions): OrganizationMembership { + return workos.post( + "/user_management/organization_memberships", + OrganizationMembership::class.java, + RequestConfig.builder().data(options).build() + ) + } + + /** + * Update the details of an existing organization membership. + */ + fun updateOrganizationMembership(id: String, roleSlug: String): OrganizationMembership { + return workos.put( + "/user_management/organization_memberships/$id", + OrganizationMembership::class.java, + RequestConfig.builder().data( + UpdateOrganizationMembershipOptionsBuilder.create( + id, roleSlug + ).build() + ).build() + ) + } + + /** + * Deletes an existing organization membership. + */ + fun deleteOrganizationMembership(id: String) { + workos.delete("/user_management/organization_memberships/$id") + } + + /** + * Get the details of an existing invitation. + */ + fun getInvitation(id: String): Invitation { + return workos.get("/user_management/invitations/$id", Invitation::class.java) + } + + /** + * Get a list of all the existing invitations matching the criteria specified. + */ + fun listInvitations(options: ListInvitationsOptions? = null): Invitations { + return workos.get( + "/user_management/invitations", + Invitations::class.java, + RequestConfig.builder().data(options ?: ListInvitationsOptions()).build() + ) + } + + /** + * Sends an invitation email to the recipient. + */ + fun sendInvitation(options: SendInvitationOptions): Invitation { + return workos.post( + "/user_management/invitations", + Invitation::class.java, + RequestConfig.builder().data(options).build() + ) + } + + /** + * Revokes an existing invitation. + */ + fun revokeInvitation(id: String): Invitation { + return workos.post("/user_management/invitations/$id/revoke", Invitation::class.java) + } + + /** + * End a user's session. The user's browser should be redirected to this URL. + */ + fun getLogoutUrl(sessionId: String): String { + return URIBuilder(workos.baseUrl) + .setPath("/user_management/sessions/logout") + .addParameter("session_id", sessionId) + .toString() + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AbstractUserOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AbstractUserOptionsBuilder.kt new file mode 100644 index 00000000..7a3770be --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AbstractUserOptionsBuilder.kt @@ -0,0 +1,61 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.PasswordHashTypeEnumType + +/** + * Abstract builder for options when managing users. + * + * @param password The password to set for the user. + * @param passwordHash The hashed password to set for the user. Mutually exclusive with password. + * @param passwordHashType The algorithm originally used to hash the password, used when providing a password_hash. + * @param firstName The first name of the user. + * @param lastName The last name of the user. + * @param emailVerified Whether the user’s email address was previously verified. + */ +abstract class AbstractUserOptionsBuilder @JvmOverloads constructor( + open var password: String? = null, + open var passwordHash: String? = null, + open var passwordHashType: PasswordHashTypeEnumType? = null, + open var firstName: String? = null, + open var lastName: String? = null, + open var emailVerified: Boolean? = null, +) { + /** + * Password + */ + fun password(value: String) = apply { password = value } + + /** + * Password Hash + */ + fun passwordHash(value: String) = apply { passwordHash = value } + + /** + * Password Hash Type + */ + fun passwordHashType(value: PasswordHashTypeEnumType) = apply { passwordHashType = value } + + /** + * First Name + */ + fun firstName(value: String) = apply { firstName = value } + + /** + * Last Name + */ + fun lastName(value: String) = apply { lastName = value } + + /** + * Email Verified + * + * You should normally use the [email verification flow](https://workos.com/docs/reference/user-management/authentication/email-verification) to verify a user’s email address. + * However, if the user’s email was previously verified, or is being migrated from an + * existing user store, this can be set to true to mark it as already verified. + */ + fun emailVerified(value: Boolean) = apply { emailVerified = value } + + /** + * Generates the options object. + */ + abstract fun build(): OptionsObject +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationAdditionalOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationAdditionalOptionsBuilder.kt new file mode 100644 index 00000000..255f42d9 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationAdditionalOptionsBuilder.kt @@ -0,0 +1,52 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions + +/** + * Builder for options when authenticating with an authorization code. + * + * @param invitationCode The token of an invitation. The invitation should be in the pending state. + * @param ipAddress The IP address of the request from the user who is attempting to authenticate. + * @param userAgent The user agent of the request from the user who is attempting to authenticate. + */ +class AuthenticationAdditionalOptionsBuilder( + private var invitationCode: String? = null, + private var ipAddress: String? = null, + private var userAgent: String? = null +) { + /** + * Invitation Code + */ + fun invitationCode(value: String) = apply { invitationCode = value } + + /** + * IP Address + */ + fun ipAddress(value: String) = apply { ipAddress = value } + + /** + * User Agent + */ + fun userAgent(value: String) = apply { userAgent = value } + + /** + * Generates the AuthenticationAdditionalOptions object. + */ + fun build(): AuthenticationAdditionalOptions { + return AuthenticationAdditionalOptions( + invitationCode = this.invitationCode, + ipAddress = this.ipAddress, + userAgent = this.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(): AuthenticationAdditionalOptionsBuilder { + return AuthenticationAdditionalOptionsBuilder() + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithCodeOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithCodeOptionsBuilder.kt new file mode 100644 index 00000000..8c051778 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithCodeOptionsBuilder.kt @@ -0,0 +1,44 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithCodeOptions + +/** + * Builder for options when authenticating with an authorization code. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param code The authorization value which was passed back as a query parameter in the callback to the redirect URI. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithCodeOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val code: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithCodeOptions object. + */ + fun build(): AuthenticationWithCodeOptions { + return AuthenticationWithCodeOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "authorization_code", + code = this.code, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, code: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithCodeOptionsBuilder { + return AuthenticationWithCodeOptionsBuilder(clientId, clientSecret, code, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithEmailVerificationOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithEmailVerificationOptionsBuilder.kt new file mode 100644 index 00000000..8f03cd50 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithEmailVerificationOptionsBuilder.kt @@ -0,0 +1,47 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithEmailVerificationOptions + +/** + * Builder for options when authenticating with email verification. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param code The one-time code that was emailed to the user. + * @param pendingAuthenticationToken The authentication token returned from a failed authentication attempt due to the corresponding error. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithEmailVerificationOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val code: String, + private val pendingAuthenticationToken: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithEmailVerificationOptions object. + */ + fun build(): AuthenticationWithEmailVerificationOptions { + return AuthenticationWithEmailVerificationOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "urn:workos:oauth:grant-type:email-verification:code", + code = this.code, + pendingAuthenticationToken = this.pendingAuthenticationToken, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, code: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithEmailVerificationOptionsBuilder { + return AuthenticationWithEmailVerificationOptionsBuilder(clientId, clientSecret, code, pendingAuthenticationToken, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithMagicAuthOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithMagicAuthOptionsBuilder.kt new file mode 100644 index 00000000..2f9c0469 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithMagicAuthOptionsBuilder.kt @@ -0,0 +1,47 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithMagicAuthOptions + +/** + * Builder for options when authenticating with Magic Auth. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param email The email address of the user. + * @param code The one-time code that was emailed to the user. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithMagicAuthOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val email: String, + private val code: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithMagicAuthOptions object. + */ + fun build(): AuthenticationWithMagicAuthOptions { + return AuthenticationWithMagicAuthOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "urn:workos:oauth:grant-type:magic-auth:code", + email = this.email, + code = this.code, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, email: String, code: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithMagicAuthOptionsBuilder { + return AuthenticationWithMagicAuthOptionsBuilder(clientId, clientSecret, email, code, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithOrganizationSelectionOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithOrganizationSelectionOptionsBuilder.kt new file mode 100644 index 00000000..f4541619 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithOrganizationSelectionOptionsBuilder.kt @@ -0,0 +1,47 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithOrganizationSelectionOptions + +/** + * Builder for options when authenticating with organization selection. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param organizationId The organization the user selected to sign in to. + * @param pendingAuthenticationToken The authentication token returned from a failed authentication attempt due to the corresponding error. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithOrganizationSelectionOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val organizationId: String, + private val pendingAuthenticationToken: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithOrganizationSelectionOptions object. + */ + fun build(): AuthenticationWithOrganizationSelectionOptions { + return AuthenticationWithOrganizationSelectionOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "urn:workos:oauth:grant-type:organization-selection", + organizationId = this.organizationId, + pendingAuthenticationToken = this.pendingAuthenticationToken, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, code: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithOrganizationSelectionOptionsBuilder { + return AuthenticationWithOrganizationSelectionOptionsBuilder(clientId, clientSecret, code, pendingAuthenticationToken, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithPasswordOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithPasswordOptionsBuilder.kt new file mode 100644 index 00000000..64b9174e --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithPasswordOptionsBuilder.kt @@ -0,0 +1,47 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithPasswordOptions + +/** + * Builder for options when authenticating with email and password. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param email The email of the user. + * @param password The password of the user. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithPasswordOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val email: String, + private val password: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithPasswordOptions object. + */ + fun build(): AuthenticationWithPasswordOptions { + return AuthenticationWithPasswordOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "password", + email = this.email, + password = this.password, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, email: String, password: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithPasswordOptionsBuilder { + return AuthenticationWithPasswordOptionsBuilder(clientId, clientSecret, email, password, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithRefreshTokenOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithRefreshTokenOptionsBuilder.kt new file mode 100644 index 00000000..7c41bba9 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithRefreshTokenOptionsBuilder.kt @@ -0,0 +1,44 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithRefreshTokenOptions + +/** + * Builder for options when authenticating with refresh token. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param refreshToken The `refresh_token` received from a successful authentication response. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithRefreshTokenOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val refreshToken: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithRefreshTokenOptions object. + */ + fun build(): AuthenticationWithRefreshTokenOptions { + return AuthenticationWithRefreshTokenOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "refresh_token", + refreshToken = this.refreshToken, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, refreshToken: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithRefreshTokenOptionsBuilder { + return AuthenticationWithRefreshTokenOptionsBuilder(clientId, clientSecret, refreshToken, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithTotpOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithTotpOptionsBuilder.kt new file mode 100644 index 00000000..31e18d92 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthenticationWithTotpOptionsBuilder.kt @@ -0,0 +1,50 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.AuthenticationAdditionalOptions +import com.workos.usermanagement.types.AuthenticationWithTotpOptions + +/** + * Builder for options when authenticating with a time-based one-time password. + * + * @param clientId Identifies the application making the request to the WorkOS server. + * @param clientSecret Authenticates the application making the request to the WorkOS server. + * @param code The one-time code generated by the user's second-factor device. + * @param authenticationChallengeId The unique ID of the authentication challenge created for the TOTP factor for which the user is enrolled. + * @param pendingAuthenticationToken The authentication token returned from a failed authentication attempt due to the corresponding error. + * @param options The authentication options passed to the authentication request. + */ +class AuthenticationWithTotpOptionsBuilder( + private val clientId: String, + private val clientSecret: String, + private val code: String, + private val authenticationChallengeId: String, + private val pendingAuthenticationToken: String, + private val options: AuthenticationAdditionalOptions? = null +) { + /** + * Generates the AuthenticationWithTotpOptions object. + */ + fun build(): AuthenticationWithTotpOptions { + return AuthenticationWithTotpOptions( + clientId = this.clientId, + clientSecret = this.clientSecret, + grantType = "urn:workos:oauth:grant-type:mfa-totp", + code = this.code, + authenticationChallengeId = this.authenticationChallengeId, + pendingAuthenticationToken = this.pendingAuthenticationToken, + invitationCode = this.options?.invitationCode, + ipAddress = this.options?.ipAddress, + userAgent = this.options?.userAgent, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(clientId: String, clientSecret: String, code: String, authenticationChallengeId: String, pendingAuthenticationToken: String, options: AuthenticationAdditionalOptions? = null): AuthenticationWithTotpOptionsBuilder { + return AuthenticationWithTotpOptionsBuilder(clientId, clientSecret, code, authenticationChallengeId, pendingAuthenticationToken, options) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/AuthorizationUrlOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/AuthorizationUrlOptionsBuilder.kt new file mode 100644 index 00000000..69414753 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/AuthorizationUrlOptionsBuilder.kt @@ -0,0 +1,119 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.UserManagementProviderEnumType +import org.apache.http.client.utils.URIBuilder +import java.lang.IllegalArgumentException + +/** + * Builder for options when creating Authorization URLs. + * + * @param baseUrl The base URL to retrieve the OAuth 2.0 authorization from. + * @param clientId This value can be obtained from the Configuration page in the WorkOS dashboard. + * @param redirectUri A redirect URI to return an authorized user to. + * @param connectionId Connection ID to determine which identity provider to authenticate with. + * @param domainHint Use the domain to determine which connection and identity provider to authenticate with. + * @param loginHint Can be used to pre-fill the username/email address field of the IdP sign-in page for the user, if you know their username ahead of time. + * @param screenHint Specify which AuthKit screen users should land on upon redirection (Only applicable when provider is 'authkit'). + * @param organizationId Used to initiate SSO for an organization. The value should be a WorkOS organization ID. + * @param provider Name of the identity provider e.g. Authkit, GitHubOAuth, GoogleOAuth, or MicrosoftOAuth. + * @param state User defined information to persist application data between redirects. + */ +class AuthorizationUrlOptionsBuilder @JvmOverloads constructor( + private val baseUrl: String, + private val clientId: String, + private val redirectUri: String, + private var connectionId: String? = null, + private var domainHint: String? = null, + private var loginHint: String? = null, + private var screenHint: String? = null, + private var organizationId: String? = null, + private var provider: UserManagementProviderEnumType? = null, + private var state: String? = null +) { + /** + * Connection ID. + */ + fun connectionId(value: String) = apply { connectionId = value } + + /** + * Domain Hint. + */ + fun domainHint(value: String) = apply { domainHint = value } + + /** + * Login Hint. + */ + fun loginHint(value: String) = apply { loginHint = value } + + /** + * Screen Hint. + */ + fun screenHint(value: String) = apply { screenHint = value } + + /** + * Organization ID. + * + * You can persist the WorkOS organization ID with application user or team identifiers. + * WorkOS will use the organization ID to determine the appropriate connection and the + * IdP to direct the user to for authentication. + */ + fun organizationId(value: String) = apply { organizationId = value } + + /** + * Value used to authenticate all users with the same connection and Identity Provider. + * + * Provide the provider parameter when authenticating Google OAuth + * users, because Google OAuth does not take a user’s domain into account when logging + * in with a “Sign in with Google” button. + */ + fun provider(value: UserManagementProviderEnumType) = apply { provider = value } + + /** + * Optional parameter that a Developer can choose to include in their authorization URL. + * If included, then the redirect URI received from WorkOS will contain the exact state + * that was passed in the authorization URL. + * + * The state parameter can be used to encode arbitrary information to help restore + * application state between redirects. + */ + fun state(value: String) = apply { state = value } + + /** + * Generates the URL based on the given options. + */ + fun build(): String { + if (provider == null && connectionId == null && organizationId == null) { + throw IllegalArgumentException("Incomplete arguments. Need to specify either a 'connectionId', 'organizationId', or 'provider'.") + } + + if (provider != null && provider!!.type != "authkit" && screenHint != null) { + throw IllegalArgumentException("'screenHint' is only supported for 'authkit' provider") + } + + val uriBuilder = URIBuilder(baseUrl) + .setPath("/user_management/authorize") + .addParameter("client_id", clientId) + .addParameter("redirect_uri", redirectUri) + .addParameter("response_type", "code") + + if (connectionId != null) uriBuilder.addParameter("connection_id", connectionId) + if (domainHint != null) uriBuilder.addParameter("domain_hint", domainHint) + if (loginHint != null) uriBuilder.addParameter("login_hint", loginHint) + if (screenHint != null) uriBuilder.addParameter("screen_hint", screenHint) + if (organizationId != null) uriBuilder.addParameter("organization_id", organizationId) + if (provider != null) uriBuilder.addParameter("provider", provider!!.type) + if (state != null) uriBuilder.addParameter("state", state) + + return uriBuilder.toString() + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(baseUrl: String, clientId: String, redirectUri: String): AuthorizationUrlOptionsBuilder { + return AuthorizationUrlOptionsBuilder(baseUrl, clientId, redirectUri) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/CreateOrganizationMembershipOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/CreateOrganizationMembershipOptionsBuilder.kt new file mode 100644 index 00000000..b71d0014 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/CreateOrganizationMembershipOptionsBuilder.kt @@ -0,0 +1,42 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.CreateOrganizationMembershipOptions + +/** + * Builder for options when creating an organization membership. + * + * @param userId The id of the user. + * @param organizationId The id of the organization. + * @param roleSlug The unique role identifier. Defaults to `member`. + */ +class CreateOrganizationMembershipOptionsBuilder @JvmOverloads constructor( + private var userId: String, + private var organizationId: String, + private var roleSlug: String? = null, +) { + /** + * Role Slug + */ + fun roleSlug(value: String) = apply { roleSlug = value } + + /** + * Generates the CreateOrganizationMembershipOptions object. + */ + fun build(): CreateOrganizationMembershipOptions { + return CreateOrganizationMembershipOptions( + userId = this.userId, + organizationId = this.organizationId, + roleSlug = this.roleSlug, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(userId: String, organizationId: String): CreateOrganizationMembershipOptionsBuilder { + return CreateOrganizationMembershipOptionsBuilder(userId, organizationId) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/CreateUserOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/CreateUserOptionsBuilder.kt new file mode 100644 index 00000000..c0bd05af --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/CreateUserOptionsBuilder.kt @@ -0,0 +1,57 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.CreateUserOptions +import com.workos.usermanagement.types.PasswordHashTypeEnumType + +/** + * Builder for options when creating a user. + * + * @param email The email address of the user. + * @param password The password to set for the user. + * @param passwordHash The hashed password to set for the user. Mutually exclusive with password. + * @param passwordHashType The algorithm originally used to hash the password, used when providing a password_hash. + * @param firstName The first name of the user. + * @param lastName The last name of the user. + * @param emailVerified Whether the user’s email address was previously verified. + */ +class CreateUserOptionsBuilder @JvmOverloads constructor( + val email: String, + override var password: String? = null, + override var passwordHash: String? = null, + override var passwordHashType: PasswordHashTypeEnumType? = null, + override var firstName: String? = null, + override var lastName: String? = null, + override var emailVerified: Boolean? = null, +) : AbstractUserOptionsBuilder( + password, + passwordHash, + passwordHashType, + firstName, + lastName, + emailVerified +) { + /** + * Generates the CreateUserOptions object. + */ + override fun build(): CreateUserOptions { + return CreateUserOptions( + email = this.email, + password = this.password, + passwordHash = this.passwordHash, + passwordHashType = this.passwordHashType, + firstName = this.firstName, + lastName = this.lastName, + emailVerified = this.emailVerified, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(email: String): CreateUserOptionsBuilder { + return CreateUserOptionsBuilder(email) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/EnrolledAuthenticationFactorOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/EnrolledAuthenticationFactorOptionsBuilder.kt new file mode 100644 index 00000000..5071ad1c --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/EnrolledAuthenticationFactorOptionsBuilder.kt @@ -0,0 +1,45 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.EnrolledAuthenticationFactorOptions + +/** + * Builder for options when enrolling an MFA factor. + * + * @param totpIssuer Your application or company name displayed in the user’s authenticator app. + * @param totpUser The user’s account name displayed in their authenticator app. + */ +class EnrolledAuthenticationFactorOptionsBuilder @JvmOverloads constructor( + private var totpIssuer: String? = null, + private var totpUser: String? = null, +) { + /** + * TOTP Issuer + */ + fun totpIssuer(value: String) = apply { totpIssuer = value } + + /** + * TOTP User + */ + fun totpUser(value: String) = apply { totpUser = value } + + /** + * Generates the EnrolledAuthenticationFactorOptions object. + */ + fun build(): EnrolledAuthenticationFactorOptions { + return EnrolledAuthenticationFactorOptions( + type = "totp", + totpIssuer = this.totpIssuer, + totpUser = this.totpUser, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(): EnrolledAuthenticationFactorOptionsBuilder { + return EnrolledAuthenticationFactorOptionsBuilder() + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/ListInvitationsOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/ListInvitationsOptionsBuilder.kt new file mode 100644 index 00000000..1bc6adb7 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/ListInvitationsOptionsBuilder.kt @@ -0,0 +1,77 @@ +package com.workos.usermanagement.builders + +import com.workos.common.models.Order +import com.workos.usermanagement.types.ListInvitationsOptions + +/** + * Builder for options when listing invitations. + * + * @param email Filter invitations by their email. + * @param organizationId Filter invitations by the organization they are members of. + * @param limit Maximum number of records to return. + * @param before Pagination cursor to receive records before a provided invitations ID. + * @param after Pagination cursor to receive records after a provided invitations ID. + * @param order Sort records in either ascending or descending order by created_at timestamp: "asc" or "desc". + */ +class ListInvitationsOptionsBuilder @JvmOverloads constructor( + private var email: String? = null, + private var organizationId: String? = null, + private var limit: Int? = null, + private var before: String? = null, + private var after: String? = null, + private var order: Order? = null, +) { + /** + * Email + */ + fun email(value: String) = apply { email = value } + + /** + * Organization Id + */ + fun organizationId(value: String) = apply { organizationId = value } + + /** + * Limit + */ + fun limit(value: Int) = apply { limit = value } + + /** + * Before + */ + fun before(value: String) = apply { before = value } + + /** + * After + */ + fun after(value: String) = apply { after = value } + + /** + * Sorting Order + */ + fun order(value: Order) = apply { order = value } + + /** + * Generates the ListInvitations options. + */ + fun build(): ListInvitationsOptions { + return ListInvitationsOptions( + email = this.email, + organizationId = this.organizationId, + limit = this.limit, + before = this.before, + after = this.after, + order = this.order, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(): ListInvitationsOptionsBuilder { + return ListInvitationsOptionsBuilder() + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/ListOrganizationMembershipsOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/ListOrganizationMembershipsOptionsBuilder.kt new file mode 100644 index 00000000..de4e4d45 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/ListOrganizationMembershipsOptionsBuilder.kt @@ -0,0 +1,77 @@ +package com.workos.usermanagement.builders + +import com.workos.common.models.Order +import com.workos.usermanagement.types.ListOrganizationMembershipsOptions + +/** + * Builder for options when listing organization memberships. + * + * @param userId Filter organization memberships by their id. + * @param organizationId Filter organization memberships by the organization they are members of. + * @param limit Maximum number of records to return. + * @param before Pagination cursor to receive records before a provided organization membership ID. + * @param after Pagination cursor to receive records after a provided organization membership ID. + * @param order Sort records in either ascending or descending order by created_at timestamp: "asc" or "desc". + */ +class ListOrganizationMembershipsOptionsBuilder @JvmOverloads constructor( + private var userId: String? = null, + private var organizationId: String? = null, + private var limit: Int? = null, + private var before: String? = null, + private var after: String? = null, + private var order: Order? = null, +) { + /** + * User Id + */ + fun userId(value: String) = apply { userId = value } + + /** + * Organization Id + */ + fun organizationId(value: String) = apply { organizationId = value } + + /** + * Limit + */ + fun limit(value: Int) = apply { limit = value } + + /** + * Before + */ + fun before(value: String) = apply { before = value } + + /** + * After + */ + fun after(value: String) = apply { after = value } + + /** + * Sorting Order + */ + fun order(value: Order) = apply { order = value } + + /** + * Generates the ListOrganizationMembershipsOptions object. + */ + fun build(): ListOrganizationMembershipsOptions { + return ListOrganizationMembershipsOptions( + userId = this.userId, + organizationId = this.organizationId, + limit = this.limit, + before = this.before, + after = this.after, + order = this.order, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(): ListOrganizationMembershipsOptionsBuilder { + return ListOrganizationMembershipsOptionsBuilder() + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/ListUsersOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/ListUsersOptionsBuilder.kt new file mode 100644 index 00000000..93041a55 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/ListUsersOptionsBuilder.kt @@ -0,0 +1,77 @@ +package com.workos.usermanagement.builders + +import com.workos.common.models.Order +import com.workos.usermanagement.types.ListUsersOptions + +/** + * Builder for options when listing users. + * + * @param email Filter users by their email. + * @param organizationId Filter users by the organization they are members of. + * @param limit Maximum number of records to return. + * @param before Pagination cursor to receive records before a provided user ID. + * @param after Pagination cursor to receive records after a provided user ID. + * @param order Sort records in either ascending or descending order by created_at timestamp: "asc" or "desc". + */ +class ListUsersOptionsBuilder @JvmOverloads constructor( + private var email: String? = null, + private var organizationId: String? = null, + private var limit: Int? = null, + private var before: String? = null, + private var after: String? = null, + private var order: Order? = null, +) { + /** + * Email + */ + fun email(value: String) = apply { email = value } + + /** + * Organization Id + */ + fun organizationId(value: String) = apply { organizationId = value } + + /** + * Limit + */ + fun limit(value: Int) = apply { limit = value } + + /** + * Before + */ + fun before(value: String) = apply { before = value } + + /** + * After + */ + fun after(value: String) = apply { after = value } + + /** + * Sorting Order + */ + fun order(value: Order) = apply { order = value } + + /** + * Generates the ListUsers options. + */ + fun build(): ListUsersOptions { + return ListUsersOptions( + email = this.email, + organizationId = this.organizationId, + limit = this.limit, + before = this.before, + after = this.after, + order = this.order, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(): ListUsersOptionsBuilder { + return ListUsersOptionsBuilder() + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/ResetPasswordOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/ResetPasswordOptionsBuilder.kt new file mode 100644 index 00000000..742f30e1 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/ResetPasswordOptionsBuilder.kt @@ -0,0 +1,34 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.ResetPasswordOptions + +/** + * Builder for options when resetting a password. + * + * @param token The token query parameter from the password reset URL. + * @param newPassword The new password to set for the user. + */ +class ResetPasswordOptionsBuilder( + private var token: String, + private var newPassword: String, +) { + /** + * Generates the ResetPasswordOptions object. + */ + fun build(): ResetPasswordOptions { + return ResetPasswordOptions( + token = this.token, + newPassword = this.newPassword + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(token: String, newPassword: String): ResetPasswordOptionsBuilder { + return ResetPasswordOptionsBuilder(token, newPassword) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/SendInvitationOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/SendInvitationOptionsBuilder.kt new file mode 100644 index 00000000..3f26b3ce --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/SendInvitationOptionsBuilder.kt @@ -0,0 +1,63 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.SendInvitationOptions + +/** + * Builder for options when sending an invitation. + * + * @param email The email address of the user. + * @param organizationId The ID of the organization that the recipient will join. + * @param expiresInDays How many days the invitations will be valid for. + * @param inviterUserId The ID of the user who invites the recipient. + * @param roleSlug The role that the recipient will receive when they join the organization in the invitation. + */ +class SendInvitationOptionsBuilder @JvmOverloads constructor( + private var email: String, + private var organizationId: String? = null, + private var expiresInDays: Int? = null, + private var inviterUserId: String? = null, + private var roleSlug: String? = null, +) { + /** + * Organization ID + */ + fun organizationId(value: String) = apply { organizationId = value } + + /** + * Expires In Days + */ + fun expiresInDays(value: Int) = apply { expiresInDays = value } + + /** + * Inviter User Id + */ + fun inviterUserId(value: String) = apply { inviterUserId = value } + + /** + * Role Slug + */ + fun roleSlug(value: String) = apply { roleSlug = value } + + /** + * Generates the SendInvitationOptions object. + */ + fun build(): SendInvitationOptions { + return SendInvitationOptions( + email = this.email, + organizationId = this.organizationId, + expiresInDays = this.expiresInDays, + inviterUserId = this.inviterUserId, + roleSlug = this.roleSlug, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(email: String): SendInvitationOptionsBuilder { + return SendInvitationOptionsBuilder(email) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/SendMagicAuthCodeOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/SendMagicAuthCodeOptionsBuilder.kt new file mode 100644 index 00000000..cd5e7833 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/SendMagicAuthCodeOptionsBuilder.kt @@ -0,0 +1,31 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.SendMagicAuthCodeOptions + +/** + * Builder for options when sending a magic auth code. + * + * @param email The email address of the user. + */ +class SendMagicAuthCodeOptionsBuilder @JvmOverloads constructor( + private var email: String, +) { + /** + * Generates the SendMagicAuthCodeOptions object. + */ + fun build(): SendMagicAuthCodeOptions { + return SendMagicAuthCodeOptions( + email = this.email, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(email: String): SendMagicAuthCodeOptionsBuilder { + return SendMagicAuthCodeOptionsBuilder(email) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/SendPasswordResetEmailOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/SendPasswordResetEmailOptionsBuilder.kt new file mode 100644 index 00000000..8c18f70c --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/SendPasswordResetEmailOptionsBuilder.kt @@ -0,0 +1,34 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.SendPasswordResetEmailOptions + +/** + * Builder for options when sending a password reset email. + * + * @param email The email address of the user. + * @param passwordResetUrl The URL to include in the email. + */ +class SendPasswordResetEmailOptionsBuilder( + private var email: String, + private var passwordResetUrl: String, +) { + /** + * Generates the SendPasswordResetEmailOptions object. + */ + fun build(): SendPasswordResetEmailOptions { + return SendPasswordResetEmailOptions( + email = this.email, + passwordResetUrl = this.passwordResetUrl + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(email: String, passwordResetUrl: String): SendPasswordResetEmailOptionsBuilder { + return SendPasswordResetEmailOptionsBuilder(email, passwordResetUrl) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/UpdateOrganizationMembershipOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/UpdateOrganizationMembershipOptionsBuilder.kt new file mode 100644 index 00000000..44ad29f8 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/UpdateOrganizationMembershipOptionsBuilder.kt @@ -0,0 +1,35 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.UpdateOrganizationMembershipOptions + +/** + * Builder for options when creating an organization membership. + * + * @param userId The id of the user. + * @param organizationId The id of the organization. + * @param roleSlug The unique role identifier. + */ +class UpdateOrganizationMembershipOptionsBuilder @JvmOverloads constructor( + private var id: String, + private var roleSlug: String, +) { + /** + * Generates the CreateOrganizationMembershipOptions object. + */ + fun build(): UpdateOrganizationMembershipOptions { + return UpdateOrganizationMembershipOptions( + id = this.id, + roleSlug = this.roleSlug, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(id: String, roleSlug: String): UpdateOrganizationMembershipOptionsBuilder { + return UpdateOrganizationMembershipOptionsBuilder(id, roleSlug) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/builders/UpdateUserOptionsBuilder.kt b/src/main/kotlin/com/workos/usermanagement/builders/UpdateUserOptionsBuilder.kt new file mode 100644 index 00000000..8f01c9c5 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/builders/UpdateUserOptionsBuilder.kt @@ -0,0 +1,57 @@ +package com.workos.usermanagement.builders + +import com.workos.usermanagement.types.PasswordHashTypeEnumType +import com.workos.usermanagement.types.UpdateUserOptions + +/** + * Builder for options when updating a user. + * + * @param id The unique ID of the user. + * @param firstName The first name of the user. + * @param lastName The last name of the user. + * @param emailVerified Whether the user’s email address was previously verified. + * @param password The password to set for the user. + * @param passwordHash The hashed password to set for the user. Mutually exclusive with password. + * @param passwordHashType The algorithm originally used to hash the password, used when providing a password_hash. + */ +class UpdateUserOptionsBuilder @JvmOverloads constructor( + val id: String, + override var firstName: String? = null, + override var lastName: String? = null, + override var emailVerified: Boolean? = null, + override var password: String? = null, + override var passwordHash: String? = null, + override var passwordHashType: PasswordHashTypeEnumType? = null, +) : AbstractUserOptionsBuilder( + password, + passwordHash, + passwordHashType, + firstName, + lastName, + emailVerified +) { + /** + * Generates the UpdateUserOptions object. + */ + override fun build(): UpdateUserOptions { + return UpdateUserOptions( + id = this.id, + firstName = this.firstName, + lastName = this.lastName, + emailVerified = this.emailVerified, + password = this.password, + passwordHash = this.passwordHash, + passwordHashType = this.passwordHashType, + ) + } + + /** + * @suppress + */ + companion object { + @JvmStatic + fun create(id: String): UpdateUserOptionsBuilder { + return UpdateUserOptionsBuilder(id) + } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/models/Authentication.kt b/src/main/kotlin/com/workos/usermanagement/models/Authentication.kt new file mode 100644 index 00000000..d2e450ab --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/Authentication.kt @@ -0,0 +1,30 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An authentication object + * + * @param user The corresponding [User] object. + * @param organizationId The organization the user selected to sign in to. + * @param accessToken A JWT containing information about the session. + * @param refreshToken Exchange this token for a new access token. + * @param impersonator An impersonation definition. + */ +data class Authentication @JsonCreator constructor( + @JsonProperty("user") + val user: User? = null, + + @JsonProperty("organization_id") + val organizationId: String? = null, + + @JsonProperty("access_token") + val accessToken: String? = null, + + @JsonProperty("refresh_token") + val refreshToken: String? = null, + + @JsonProperty("impersonator") + val impersonator: AuthenticationImpersonator? = null, +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/AuthenticationChallenge.kt b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationChallenge.kt new file mode 100644 index 00000000..618c3550 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationChallenge.kt @@ -0,0 +1,30 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An authentication challenge + * + * @param id The unique ID of the challenge. + * @param createdAt The timestamp when the challenge was created. + * @param updatedAt The timestamp when the challenge was last updated. + * @param expiresAt The timestamp when the challenge will expire. + * @param authenticationFactorId The unique ID of the authentication factor the challenge belongs to. + */ +data class AuthenticationChallenge @JsonCreator constructor( + @JsonProperty("id") + val id: String, + + @JsonProperty("created_at") + val createdAt: String, + + @JsonProperty("updated_at") + val updatedAt: String, + + @JsonProperty("expires_at") + val expiresAt: String? = null, + + @JsonProperty("authentication_factor_id") + val authenticationFactorId: String +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactor.kt b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactor.kt new file mode 100644 index 00000000..8199c35d --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactor.kt @@ -0,0 +1,34 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An authentication factor + * + * @param id The unique ID of the factor. + * @param createdAt The timestamp when the factor was created. + * @param updatedAt The timestamp when the factor was last updated. + * @param type The type of the factor to enroll. The only available option is TOTP. + * @param totp Time-based one-time password (see [AuthenticationTotp]). + * @param userId The ID of the user. + */ +data class AuthenticationFactor @JsonCreator constructor( + @JsonProperty("id") + val id: String, + + @JsonProperty("created_at") + val createdAt: String, + + @JsonProperty("updated_at") + val updatedAt: String, + + @JsonProperty("type") + val type: String, + + @JsonProperty("totp") + val totp: AuthenticationTotp? = null, + + @JsonProperty("user_id") + val userId: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactors.kt b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactors.kt new file mode 100644 index 00000000..994184fe --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationFactors.kt @@ -0,0 +1,20 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.ListMetadata + +/** + * A list of authentication factors + * + * @param data A list of [AuthenticationFactor]s ordered by creation time. + * @param listMetadata [com.workos.common.models.ListMetadata]. + */ +data class AuthenticationFactors +@JsonCreator constructor( + @JsonProperty("data") + val data: List, + + @JsonProperty("list_metadata") + val listMetadata: ListMetadata +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/AuthenticationImpersonator.kt b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationImpersonator.kt new file mode 100644 index 00000000..8a31e18b --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationImpersonator.kt @@ -0,0 +1,18 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An authentication impersonator object. + * + * @param email The email address of the WorkOS Dashboard user who is impersonating the user. + * @param reason The justification the impersonator gave for impersonating the user. + */ +data class AuthenticationImpersonator @JsonCreator constructor( + @JsonProperty("email") + val email: String, + + @JsonProperty("reason") + val reason: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/AuthenticationTotp.kt b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationTotp.kt new file mode 100644 index 00000000..5e6889bb --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/AuthenticationTotp.kt @@ -0,0 +1,30 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An authentication TOTP + * + * @param issuer Your application or company name displayed in the user’s authenticator app. Defaults to your WorkOS team name. + * @param user The user’s account name displayed in their authenticator app. Defaults to the user’s email. + * @param qrCode Base64 encoded image containing scannable QR code. + * @param secret TOTP secret that can be manually entered into some authenticator apps in place of scanning a QR code. + * @param uri The `otpauth` URI that is encoded by the provided `qr_code`. + */ +data class AuthenticationTotp @JsonCreator constructor( + @JsonProperty("issuer") + val issuer: String? = null, + + @JsonProperty("user") + val user: String? = null, + + @JsonProperty("qr_code") + val qrCode: String? = null, + + @JsonProperty("secret") + val secret: String? = null, + + @JsonProperty("uri") + val uri: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/EnrolledAuthenticationFactor.kt b/src/main/kotlin/com/workos/usermanagement/models/EnrolledAuthenticationFactor.kt new file mode 100644 index 00000000..57cdc52b --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/EnrolledAuthenticationFactor.kt @@ -0,0 +1,18 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An enrolled authentication factor object + * + * @param challenge The [AuthenticationChallenge] that is used to complete the authentication process. + * @param factor The [AuthenticationFactor] that represents the additional authentication method used on top of the existing authentication strategy. + */ +data class EnrolledAuthenticationFactor @JsonCreator constructor( + @JsonProperty("challenge") + val challenge: AuthenticationChallenge, + + @JsonProperty("factor") + val factor: AuthenticationFactor +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/Identity.kt b/src/main/kotlin/com/workos/usermanagement/models/Identity.kt new file mode 100644 index 00000000..5b02eae0 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/Identity.kt @@ -0,0 +1,23 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.usermanagement.types.IdentityProviderEnumType + +/** + * Represents `User` identities obtained from external identity providers. + * + * @param idpId The unique ID of the invitation. + * @param type The email address of the user. + * @param provider The state of the invitation (see enum values in [IdentityProviderEnumType]). + */ +data class Identity @JsonCreator constructor( + @JsonProperty("idp_id") + val idpId: String, + + @JsonProperty("type") + val type: String = "OAuth", + + @JsonProperty("provider") + val provider: IdentityProviderEnumType, +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/Invitation.kt b/src/main/kotlin/com/workos/usermanagement/models/Invitation.kt new file mode 100644 index 00000000..678467a0 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/Invitation.kt @@ -0,0 +1,53 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.usermanagement.types.InvitationStateEnumType + +/** + * An email invitation allows the recipient to sign up for your app and join a + * specific organization. When an invitation is accepted, a user and a + * corresponding organization membership are created. + * + * @param id The unique ID of the invitation. + * @param email The email address of the user. + * @param state The state of the invitation (see enum values in [InvitationStateEnumType]). + * @param acceptedAt The timestamp when the invitation was accepted. + * @param revokedAt The timestamp when the invitation was revoked. + * @param expiresAt The timestamp when the invitation will expire. + * @param token The token of an invitation. + * @param organizationId The ID of the organization. + * @param createdAt The timestamp when the invitation was created. + * @param updatedAt The timestamp when the invitation was last updated. + */ +data class Invitation @JsonCreator constructor( + @JsonProperty("id") + val id: String, + + @JsonProperty("email") + val email: String, + + @JsonProperty("state") + val state: InvitationStateEnumType, + + @JsonProperty("accepted_at") + val acceptedAt: String? = null, + + @JsonProperty("revoked_at") + val revokedAt: String? = null, + + @JsonProperty("expires_at") + val expiresAt: String, + + @JsonProperty("token") + val token: String, + + @JsonProperty("organization_id") + val organizationId: String? = null, + + @JsonProperty("created_at") + val createdAt: String, + + @JsonProperty("updated_at") + val updatedAt: String +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/Invitations.kt b/src/main/kotlin/com/workos/usermanagement/models/Invitations.kt new file mode 100644 index 00000000..8d9a7d08 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/Invitations.kt @@ -0,0 +1,20 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.ListMetadata + +/** + * A list of [Invitation]s + * + * @param data A list of [Invitation]s order by creation time + * @param listMetadata [com.workos.common.models.ListMetadata]. + */ +data class Invitations +@JsonCreator constructor( + @JsonProperty("data") + val data: List, + + @JsonProperty("list_metadata") + val listMetadata: ListMetadata +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembership.kt b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembership.kt new file mode 100644 index 00000000..f9bab08f --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembership.kt @@ -0,0 +1,40 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.usermanagement.types.OrganizationMembershipStatusEnumType + +/** + * An organization membership is a top-level resource that represents a [User]’s relationship + * with an organization. A user may be a member of zero, one, or many organizations. + * + * @param id The unique ID of the organization membership. + * @param userId The ID of the [User]. + * @param organizationId The ID of the organization which the user belongs to. + * @param role The role in the organization membership (see [OrganizationMembershipRole]). + * @param status Whether the organization membership is active or pending (see enum values in [OrganizationMembershipStatusEnumType]). + * @param createdAt The timestamp when the user was created. + * @param updatedAt The timestamp when the user was last updated. + */ +data class OrganizationMembership @JsonCreator constructor( + @JsonProperty("id") + val id: String, + + @JsonProperty("user_id") + val userId: String, + + @JsonProperty("organization_id") + val organizationId: String, + + @JsonProperty("role") + val role: OrganizationMembershipRole? = null, + + @JsonProperty("status") + val status: OrganizationMembershipStatusEnumType, + + @JsonProperty("created_at") + val createdAt: String, + + @JsonProperty("updated_at") + val updatedAt: String +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembershipRole.kt b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembershipRole.kt new file mode 100644 index 00000000..709d1c1f --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMembershipRole.kt @@ -0,0 +1,14 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * An organization membership role. + * + * @param slug The unique role identified. + */ +data class OrganizationMembershipRole @JsonCreator constructor( + @JsonProperty("slug") + val slug: String +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/OrganizationMemberships.kt b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMemberships.kt new file mode 100644 index 00000000..c35bfe06 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/OrganizationMemberships.kt @@ -0,0 +1,20 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.ListMetadata + +/** + * A list of WorkOS [OrganizationMembership]s + * + * @param data A list of [OrganizationMembership]s ordered by creation time. + * @param listMetadata [com.workos.common.models.ListMetadata]. + */ +data class OrganizationMemberships +@JsonCreator constructor( + @JsonProperty("data") + val data: List, + + @JsonProperty("list_metadata") + val listMetadata: ListMetadata +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/RefreshAuthentication.kt b/src/main/kotlin/com/workos/usermanagement/models/RefreshAuthentication.kt new file mode 100644 index 00000000..68d73c15 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/RefreshAuthentication.kt @@ -0,0 +1,18 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * A refresh authentication object + * + * @param accessToken A JWT containing information about the session. + * @param refreshToken Exchange this token for a new access token. + */ +data class RefreshAuthentication @JsonCreator constructor( + @JsonProperty("access_token") + val accessToken: String, + + @JsonProperty("refresh_token") + val refreshToken: String, +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/User.kt b/src/main/kotlin/com/workos/usermanagement/models/User.kt new file mode 100644 index 00000000..3a1c7932 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/User.kt @@ -0,0 +1,42 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty + +/** + * A WorkOS user + * + * @param id The unique ID of the user. + * @param email The email address of the user. + * @param firstName The first name of the user. + * @param lastName The last name of the user. + * @param emailVerified Whether the user’s email has been verified. + * @param profilePictureUrl A URL reference to an image representing the user. + * @param createdAt The timestamp when the user was created. + * @param updatedAt The timestamp when the user was last updated. + */ +data class User @JsonCreator constructor( + @JsonProperty("id") + val id: String, + + @JsonProperty("email") + val email: String, + + @JsonProperty("first_name") + val firstName: String? = null, + + @JsonProperty("last_name") + val lastName: String? = null, + + @JsonProperty("email_verified") + val emailVerified: Boolean, + + @JsonProperty("profile_picture_url") + val profilePictureUrl: String? = null, + + @JsonProperty("created_at") + val createdAt: String, + + @JsonProperty("updated_at") + val updatedAt: String +) diff --git a/src/main/kotlin/com/workos/usermanagement/models/Users.kt b/src/main/kotlin/com/workos/usermanagement/models/Users.kt new file mode 100644 index 00000000..f896490e --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/models/Users.kt @@ -0,0 +1,20 @@ +package com.workos.usermanagement.models + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.ListMetadata + +/** + * A list of WorkOS [User]s + * + * @param data A list of [User]s. + * @param listMetadata [com.workos.common.models.ListMetadata]. + */ +data class Users +@JsonCreator constructor( + @JsonProperty("data") + val data: List, + + @JsonProperty("list_metadata") + val listMetadata: ListMetadata +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationAdditionalOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationAdditionalOptions.kt new file mode 100644 index 00000000..c9c6aa46 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationAdditionalOptions.kt @@ -0,0 +1,34 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +open class AuthenticationAdditionalOptions( + /** + * The token of an invitation. The invitation should be in the pending state. + * + * When a valid invitation token is specified, the user is able to sign up even + * if it is disabled in the environment. Additionally, if the invitation was for + * a specific organization, attaching the token to a user's authenticate call + * automatically provisions their membership to the organization. + */ + @JsonProperty("invitation_code") + open val invitationCode: String? = null, + + /** + * The IP address of the request from the user who is attempting to authenticate. + * + * Refer to your web framework or server documentation for the correct way to + * obtain the user’s actual IP address. If your application receives requests + * from a reverse proxy, you may need to retrieve this from a special header + * like `X-Forward-For`. + */ + @JsonProperty("ip_address") + open val ipAddress: String? = null, + + /** + * The user agent of the request from the user who is attempting to authenticate. + * This should be the value of the `User-Agent` header. + */ + @JsonProperty("user_agent") + open val userAgent: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithCodeOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithCodeOptions.kt new file mode 100644 index 00000000..dceb8423 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithCodeOptions.kt @@ -0,0 +1,48 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithCodeOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The authorization value which was passed back as a query parameter in the + * callback to the redirect URI. + */ + @JsonProperty("code") + val code: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(code.isNotBlank()) { "Code is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithEmailVerificationOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithEmailVerificationOptions.kt new file mode 100644 index 00000000..d79f0959 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithEmailVerificationOptions.kt @@ -0,0 +1,54 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithEmailVerificationOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The one-time code that was emailed to the user. + */ + @JsonProperty("code") + val code: String, + + /** + * The authentication token returned from a failed authentication attempt due to the corresponding error. + */ + @JsonProperty("pending_authentication_token") + val pendingAuthenticationToken: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(code.isNotBlank()) { "Code is required" } + require(pendingAuthenticationToken.isNotBlank()) { "Pending Authentication Token is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithMagicAuthOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithMagicAuthOptions.kt new file mode 100644 index 00000000..76d6ac86 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithMagicAuthOptions.kt @@ -0,0 +1,54 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithMagicAuthOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The email address of the user. + */ + @JsonProperty("email") + val email: String, + + /** + * The one-time code that was emailed to the user. + */ + @JsonProperty("code") + val code: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(code.isNotBlank()) { "Code is required" } + require(email.isNotBlank()) { "Email is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithOrganizationSelectionOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithOrganizationSelectionOptions.kt new file mode 100644 index 00000000..bfc45bbf --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithOrganizationSelectionOptions.kt @@ -0,0 +1,54 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithOrganizationSelectionOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The organization the user selected to sign in to. + */ + @JsonProperty("organization_id") + val organizationId: String, + + /** + * The authentication token returned from a failed authentication attempt due to the corresponding error. + */ + @JsonProperty("pending_authentication_token") + val pendingAuthenticationToken: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(organizationId.isNotBlank()) { "Organization ID is required" } + require(pendingAuthenticationToken.isNotBlank()) { "Pending Authentication Token is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithPasswordOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithPasswordOptions.kt new file mode 100644 index 00000000..235e0b06 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithPasswordOptions.kt @@ -0,0 +1,53 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithPasswordOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The email address of the user. + */ + @JsonProperty("email") + val email: String, + + /** + * The password of the user. + */ + @JsonProperty("password") + val password: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(email.isNotBlank()) { "Email is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithRefreshTokenOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithRefreshTokenOptions.kt new file mode 100644 index 00000000..c43319d1 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithRefreshTokenOptions.kt @@ -0,0 +1,47 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithRefreshTokenOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The `refresh_token` received from a successful authentication response. + */ + @JsonProperty("refresh_token") + val refreshToken: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(refreshToken.isNotBlank()) { "Refresh Token is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithTotpOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithTotpOptions.kt new file mode 100644 index 00000000..6b720296 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/AuthenticationWithTotpOptions.kt @@ -0,0 +1,60 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class AuthenticationWithTotpOptions @JvmOverloads constructor( + /** + * Identifies the application making the request to the WorkOS server. + */ + @JsonProperty("client_id") + val clientId: String, + + /** + * Authenticates the application making the request to the WorkOS server. + */ + @JsonProperty("client_secret") + val clientSecret: String, + + /** + * A string constant that distinguishes the method by which your application + * will receive an access token. + */ + @JsonProperty("grant_type") + val grantType: String, + + /** + * The one-time code that was emailed to the user. + */ + @JsonProperty("code") + val code: String, + + /** + * The unique ID of the authentication challenge created for the TOTP factor for which the user is enrolled. + */ + @JsonProperty("authentication_challenge_id") + val authenticationChallengeId: String, + + /** + * The authentication token returned from a failed authentication attempt due to the corresponding error. + */ + @JsonProperty("pending_authentication_token") + val pendingAuthenticationToken: String, + + @JsonProperty("invitation_code") + override val invitationCode: String? = null, + + @JsonProperty("ip_address") + override val ipAddress: String? = null, + + @JsonProperty("user_agent") + override val userAgent: String? = null +) : AuthenticationAdditionalOptions(invitationCode, ipAddress, userAgent) { + init { + require(clientId.isNotBlank()) { "Client ID is required" } + require(clientSecret.isNotBlank()) { "Client Secret is required" } + require(authenticationChallengeId.isNotBlank()) { "Authentication Challenge ID is required" } + require(pendingAuthenticationToken.isNotBlank()) { "Pending Authentication Token is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/CreateOrganizationMembershipOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/CreateOrganizationMembershipOptions.kt new file mode 100644 index 00000000..5efe30f5 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/CreateOrganizationMembershipOptions.kt @@ -0,0 +1,30 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class CreateOrganizationMembershipOptions @JvmOverloads constructor( + /** + * The id of the user. + */ + @JsonProperty("user_id") + val userId: String, + + /** + * The id of the organization. + */ + @JsonProperty("organization_id") + val organizationId: String, + + /** + * The unique role identifier. Defaults to `member`. + */ + @JsonProperty("role_slug") + val roleSlug: String? = null +) { + init { + require(userId.isNotBlank()) { "User ID is required" } + require(organizationId.isNotBlank()) { "Organization ID is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/CreateUserOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/CreateUserOptions.kt new file mode 100644 index 00000000..b36d7319 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/CreateUserOptions.kt @@ -0,0 +1,55 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class CreateUserOptions @JvmOverloads constructor( + /** + * The email address of the user. + */ + @JsonProperty("email") + val email: String, + + /** + * The password to set for the user. + */ + @JsonProperty("password") + val password: String? = null, + + /** + * The hashed password to set for the user. Mutually exclusive with password. + */ + @JsonProperty("password_hash") + val passwordHash: String? = null, + + /** + * The algorithm originally used to hash the password, used when providing a password_hash. + */ + @JsonProperty("password_hash_type") + val passwordHashType: PasswordHashTypeEnumType? = null, + + /** + * The first name of the user. + */ + @JsonProperty("first_name") + val firstName: String? = null, + + /** + * The last name of the user. + */ + @JsonProperty("last_name") + val lastName: String? = null, + + /** + * Whether the user’s email address was previously verified. + * + * You should normally use the email verification flow to verify a user’s email address. However, if the user’s email was previously verified, or is being migrated from an existing user store, this can be set to true to mark it as already verified. + */ + @JsonProperty("email_verified") + val emailVerified: Boolean? = null +) { + init { + require(email.isNotBlank()) { "Email is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/EnrolledAuthenticationFactorOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/EnrolledAuthenticationFactorOptions.kt new file mode 100644 index 00000000..fd658bed --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/EnrolledAuthenticationFactorOptions.kt @@ -0,0 +1,25 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class EnrolledAuthenticationFactorOptions @JvmOverloads constructor( + /** + * The type of the factor to enroll. The only available option is TOTP. + */ + @JsonProperty("type") + val type: String = "totp", + + /** + * Your application or company name displayed in the user’s authenticator app. Defaults to your WorkOS team name. + */ + @JsonProperty("totp_issuer") + val totpIssuer: String? = null, + + /** + * The user’s account name displayed in their authenticator app. Defaults to the user’s email. + */ + @JsonProperty("totp_user") + val totpUser: String? = null, +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/IdentityProviderEnumType.kt b/src/main/kotlin/com/workos/usermanagement/types/IdentityProviderEnumType.kt new file mode 100644 index 00000000..6cc471de --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/IdentityProviderEnumType.kt @@ -0,0 +1,23 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class IdentityProviderEnumType(val type: String) { + /** + * GitHub OAuth + */ + @JsonProperty("GitHubOAuth") + GitHubOAuth("GitHubOAuth"), + + /** + * Google OAuth + */ + @JsonProperty("GoogleOAuth") + GoogleOAuth("GoogleOAuth"), + + /** + * Microsoft OAuth + */ + @JsonProperty("MicrosoftOAuth") + MicrosoftOAuth("MicrosoftOAuth") +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/InvitationStateEnumType.kt b/src/main/kotlin/com/workos/usermanagement/types/InvitationStateEnumType.kt new file mode 100644 index 00000000..715e2c06 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/InvitationStateEnumType.kt @@ -0,0 +1,29 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class InvitationStateEnumType(val type: String) { + /** + * Accepted + */ + @JsonProperty("accepted") + Accepted("accepted"), + + /** + * Pending + */ + @JsonProperty("pending") + Pending("pending"), + + /** + * Expired + */ + @JsonProperty("expired") + Expired("expired"), + + /** + * Revoked + */ + @JsonProperty("revoked") + Revoked("revoked"), +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/ListInvitationsOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/ListInvitationsOptions.kt new file mode 100644 index 00000000..50fbfef3 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/ListInvitationsOptions.kt @@ -0,0 +1,26 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.Order + +@JsonInclude(JsonInclude.Include.NON_NULL) +class ListInvitationsOptions @JvmOverloads constructor( + @JsonProperty("email") + val email: String? = null, + + @JsonProperty("organization_id") + val organizationId: String? = null, + + @JsonProperty("limit") + val limit: Int? = null, + + @JsonProperty("order") + val order: Order? = null, + + @JsonProperty("before") + val before: String? = null, + + @JsonProperty("after") + val after: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/ListOrganizationMembershipsOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/ListOrganizationMembershipsOptions.kt new file mode 100644 index 00000000..83ea6b5d --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/ListOrganizationMembershipsOptions.kt @@ -0,0 +1,26 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.Order + +@JsonInclude(JsonInclude.Include.NON_NULL) +class ListOrganizationMembershipsOptions @JvmOverloads constructor( + @JsonProperty("user_id") + val userId: String? = null, + + @JsonProperty("organization_id") + val organizationId: String? = null, + + @JsonProperty("limit") + val limit: Int? = null, + + @JsonProperty("order") + val order: Order? = null, + + @JsonProperty("before") + val before: String? = null, + + @JsonProperty("after") + val after: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/ListUsersOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/ListUsersOptions.kt new file mode 100644 index 00000000..e16347f9 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/ListUsersOptions.kt @@ -0,0 +1,26 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty +import com.workos.common.models.Order + +@JsonInclude(JsonInclude.Include.NON_NULL) +class ListUsersOptions @JvmOverloads constructor( + @JsonProperty("email") + val email: String? = null, + + @JsonProperty("organization_id") + val organizationId: String? = null, + + @JsonProperty("limit") + val limit: Int? = null, + + @JsonProperty("order") + val order: Order? = null, + + @JsonProperty("before") + val before: String? = null, + + @JsonProperty("after") + val after: String? = null +) diff --git a/src/main/kotlin/com/workos/usermanagement/types/OrganizationMembershipStatusEnumType.kt b/src/main/kotlin/com/workos/usermanagement/types/OrganizationMembershipStatusEnumType.kt new file mode 100644 index 00000000..c82ee7e9 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/OrganizationMembershipStatusEnumType.kt @@ -0,0 +1,17 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class OrganizationMembershipStatusEnumType(val type: String) { + /** + * Active + */ + @JsonProperty("active") + Active("active"), + + /** + * Pending + */ + @JsonProperty("pending") + Pending("pending"), +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/PasswordHashTypeEnumType.kt b/src/main/kotlin/com/workos/usermanagement/types/PasswordHashTypeEnumType.kt new file mode 100644 index 00000000..f61ef396 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/PasswordHashTypeEnumType.kt @@ -0,0 +1,23 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class PasswordHashTypeEnumType(val type: String) { + /** + * Bcrypt + */ + @JsonProperty("bcrypt") + Bcrypt("bcrypt"), + + /** + * Firebase-scrypt + */ + @JsonProperty("firebase-scrypt") + FirebaseScrypt("firebase-scrypt"), + + /** + * Ssha + */ + @JsonProperty("ssha") + Ssha("ssha"), +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/ResetPasswordOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/ResetPasswordOptions.kt new file mode 100644 index 00000000..9a4fbfd2 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/ResetPasswordOptions.kt @@ -0,0 +1,22 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +class ResetPasswordOptions( + /** + * The token query parameter from the password reset URL. + */ + @JsonProperty("token") + val token: String, + + /** + * The new password to set for the user. + */ + @JsonProperty("new_password") + val newPassword: String, +) { + init { + require(token.isNotBlank()) { "Token is required" } + require(newPassword.isNotBlank()) { "New Password is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/SendInvitationOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/SendInvitationOptions.kt new file mode 100644 index 00000000..5d735a15 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/SendInvitationOptions.kt @@ -0,0 +1,41 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +class SendInvitationOptions( + /** + * The email address of the recipient. + */ + @JsonProperty("email") + val email: String, + + /** + * The ID of the organization that the recipient will join. + */ + @JsonProperty("organization_id") + val organizationId: String? = null, + + /** + * How many days the invitations will be valid for. + * Must be between 1 and 30 days. Defaults to 7 days if not specified. + */ + @JsonProperty("expires_in_days") + val expiresInDays: Int? = null, + + /** + * The ID of the user who invites the recipient. + * The invitation email will mention the name of this user. + */ + @JsonProperty("inviter_user_id") + val inviterUserId: String? = null, + + /** + * The role that the recipient will receive when they join the organization in the invitation. + */ + @JsonProperty("role_slug") + val roleSlug: String? = null, +) { + init { + require(email.isNotBlank()) { "Email is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/SendMagicAuthCodeOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/SendMagicAuthCodeOptions.kt new file mode 100644 index 00000000..dd412eff --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/SendMagicAuthCodeOptions.kt @@ -0,0 +1,15 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +class SendMagicAuthCodeOptions( + /** + * The email address of the user. + */ + @JsonProperty("email") + val email: String, +) { + init { + require(email.isNotBlank()) { "Email is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/SendPasswordResetEmailOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/SendPasswordResetEmailOptions.kt new file mode 100644 index 00000000..ec2c9cba --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/SendPasswordResetEmailOptions.kt @@ -0,0 +1,22 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +class SendPasswordResetEmailOptions( + /** + * The email address of the user who requested to reset their password. + */ + @JsonProperty("email") + val email: String, + + /** + * The URL to include in the email. + */ + @JsonProperty("password_reset_url") + val passwordResetUrl: String, +) { + init { + require(email.isNotBlank()) { "Email is required" } + require(passwordResetUrl.isNotBlank()) { "Password reset URL is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/UpdateOrganizationMembershipOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/UpdateOrganizationMembershipOptions.kt new file mode 100644 index 00000000..168577ef --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/UpdateOrganizationMembershipOptions.kt @@ -0,0 +1,23 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class UpdateOrganizationMembershipOptions @JvmOverloads constructor( + /** + * The id of the organization membership. + */ + @JsonProperty("id") + val id: String, + + /** + * The unique role identifier. Defaults to `member`. + */ + @JsonProperty("role_slug") + val roleSlug: String +) { + init { + require(id.isNotBlank()) { "Organization Membership ID is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/UpdateUserOptions.kt b/src/main/kotlin/com/workos/usermanagement/types/UpdateUserOptions.kt new file mode 100644 index 00000000..65099d58 --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/UpdateUserOptions.kt @@ -0,0 +1,53 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonInclude(JsonInclude.Include.NON_NULL) +class UpdateUserOptions @JvmOverloads constructor( + /** + * The unique ID of the user. + */ + @JsonProperty("id") + val id: String, + + /** + * The first name of the user. + */ + @JsonProperty("first_name") + val firstName: String? = null, + + /** + * The last name of the user. + */ + @JsonProperty("last_name") + val lastName: String? = null, + + /** + * Whether the user’s email address was previously verified. + */ + @JsonProperty("email_verified") + val emailVerified: Boolean? = null, + + /** + * The password to set for the user. + */ + @JsonProperty("password") + val password: String? = null, + + /** + * The hashed password to set for the user. Mutually exclusive with password. + */ + @JsonProperty("password_hash") + val passwordHash: String? = null, + + /** + * The algorithm originally used to hash the password, used when providing a password_hash. + */ + @JsonProperty("password_hash_type") + val passwordHashType: PasswordHashTypeEnumType? = null +) { + init { + require(id.isNotBlank()) { "User id is required" } + } +} diff --git a/src/main/kotlin/com/workos/usermanagement/types/UserManagementProviderEnumType.kt b/src/main/kotlin/com/workos/usermanagement/types/UserManagementProviderEnumType.kt new file mode 100644 index 00000000..9a40946b --- /dev/null +++ b/src/main/kotlin/com/workos/usermanagement/types/UserManagementProviderEnumType.kt @@ -0,0 +1,29 @@ +package com.workos.usermanagement.types + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class UserManagementProviderEnumType(val type: String) { + /** + * AuthKit + */ + @JsonProperty("authkit") + AuthKit("authkit"), + + /** + * GitHub OAuth + */ + @JsonProperty("GitHubOAuth") + GitHubOAuth("GitHubOAuth"), + + /** + * Google OAuth + */ + @JsonProperty("GoogleOAuth") + GoogleOAuth("GoogleOAuth"), + + /** + * Microsoft OAuth + */ + @JsonProperty("MicrosoftOAuth") + MicrosoftOAuth("MicrosoftOAuth") +} diff --git a/src/test/kotlin/com/workos/test/user_management/UserManagementApiTest.kt b/src/test/kotlin/com/workos/test/user_management/UserManagementApiTest.kt new file mode 100644 index 00000000..a6d782ef --- /dev/null +++ b/src/test/kotlin/com/workos/test/user_management/UserManagementApiTest.kt @@ -0,0 +1,1315 @@ +package com.workos.test.usermanagement + +import com.workos.common.models.ListMetadata +import com.workos.common.models.Order +import com.workos.test.TestBase +import com.workos.usermanagement.builders.AuthenticationAdditionalOptionsBuilder +import com.workos.usermanagement.builders.CreateOrganizationMembershipOptionsBuilder +import com.workos.usermanagement.builders.CreateUserOptionsBuilder +import com.workos.usermanagement.builders.EnrolledAuthenticationFactorOptionsBuilder +import com.workos.usermanagement.builders.ListInvitationsOptionsBuilder +import com.workos.usermanagement.builders.ListOrganizationMembershipsOptionsBuilder +import com.workos.usermanagement.builders.ListUsersOptionsBuilder +import com.workos.usermanagement.builders.SendInvitationOptionsBuilder +import com.workos.usermanagement.builders.UpdateUserOptionsBuilder +import com.workos.usermanagement.models.AuthenticationChallenge +import com.workos.usermanagement.models.AuthenticationFactor +import com.workos.usermanagement.models.AuthenticationTotp +import com.workos.usermanagement.models.EnrolledAuthenticationFactor +import com.workos.usermanagement.models.Identity +import com.workos.usermanagement.models.Invitation +import com.workos.usermanagement.models.OrganizationMembership +import com.workos.usermanagement.models.OrganizationMembershipRole +import com.workos.usermanagement.models.RefreshAuthentication +import com.workos.usermanagement.models.User +import com.workos.usermanagement.types.IdentityProviderEnumType +import com.workos.usermanagement.types.InvitationStateEnumType +import com.workos.usermanagement.types.OrganizationMembershipStatusEnumType +import com.workos.usermanagement.types.UserManagementProviderEnumType +import org.junit.jupiter.api.Assertions.assertDoesNotThrow +import org.junit.jupiter.api.Assertions.assertThrows +import kotlin.test.Test +import kotlin.test.assertEquals + +class UserManagementApiTest : TestBase() { + val workos = createWorkOSClient() + + @Test + fun getUserShouldReturnValidUserObject() { + stubResponse( + "/user_management/users/user_123", + """{ + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "email_verified": true, + "profile_picture_url": "https://example.com/profile_picture.jpg", + "first_name": "Test", + "last_name": "User", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""" + ) + + val user = workos.userManagement.getUser("user_123") + + assertEquals( + User( + "user_123", + "test01@example.com", + "Test", + "User", + true, + "https://example.com/profile_picture.jpg", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + user + ) + } + + @Test + fun listUsersShouldReturnValidUsers() { + stubResponse( + "/user_management/users", + """{ + "data": [ + { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "user_234" + } + }""" + ) + + val users = workos.userManagement.listUsers(ListUsersOptionsBuilder().build()) + + assertEquals( + User( + "user_123", + "test01@example.com", + null, + null, + false, + null, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + users.data[0] + ) + assertEquals( + ListMetadata( + null, "user_234" + ), + users.listMetadata + ) + } + + @Test + fun listUsersShouldReturnValidUsersWithPaginationAndFilters() { + stubResponse( + "/user_management/users", + """{ + "data": [ + { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "user_234" + } + }""" + ) + + val options = ListUsersOptionsBuilder() + .email("test01@example.com") + .organizationId("org_123") + .order(Order.Desc) + .limit(10) + .after("someAfterId") + .before("someBeforeId") + .build() + + val users = workos.userManagement.listUsers(options) + + assertEquals( + User( + "user_123", + "test01@example.com", + null, + null, + false, + null, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + users.data[0] + ) + assertEquals( + ListMetadata( + null, "user_234" + ), + users.listMetadata + ) + } + + @Test + fun createUserShouldReturnValidUserObject() { + stubResponse( + "/user_management/users", + """{ + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "email_verified": true, + "profile_picture_url": null, + "first_name": "Test", + "last_name": "User", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "email": "test01@example.com", + "password": "password", + "first_name": "Test", + "last_name": "User", + "email_verified": true + }""" + ) + + val options = CreateUserOptionsBuilder("test01@example.com") + .password("password") + .firstName("Test") + .lastName("User") + .emailVerified(true) + .build() + + val user = workos.userManagement.createUser(options) + + assertEquals( + User( + "user_123", + "test01@example.com", + "Test", + "User", + true, + null, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + user + ) + } + + @Test + fun updateUserShouldReturnValidUserObject() { + stubResponse( + "/user_management/users/user_123", + """{ + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "email_verified": true, + "profile_picture_url": null, + "first_name": "Test", + "last_name": "User", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "id": "user_123", + "password": "password", + "first_name": "Test", + "last_name": "User", + "email_verified": true + }""" + ) + + val options = UpdateUserOptionsBuilder("user_123") + .password("password") + .firstName("Test") + .lastName("User") + .emailVerified(true) + .build() + + val user = workos.userManagement.updateUser("user_123", options) + + assertEquals( + User( + "user_123", + "test01@example.com", + "Test", + "User", + true, + null, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + user + ) + } + + @Test + fun deleteUserShouldWorkAndReturnNothing() { + stubResponse("/user_management/users/user_123", "") + + assertDoesNotThrow() { + workos.userManagement.deleteUser("user_123") + } + } + + @Test + fun getUserIdentitiesShouldReturnValidIdentitiesObject() { + stubResponse( + "/user_management/users/user_123/identities", + """[{ + "idp_id": "idp_123", + "type": "OAuth", + "provider": "MicrosoftOAuth" + }]""" + ) + + val identities = workos.userManagement.getUserIdentities("user_123") + + assertEquals( + Identity( + "idp_123", + "OAuth", + IdentityProviderEnumType.MicrosoftOAuth, + ), + identities[0] + ) + } + + @Test + fun getAuthorizationUrlShouldReturnValidUrl() { + val url = workos.userManagement.getAuthorizationUrl("client_id", "http://localhost:8080/redirect").provider(UserManagementProviderEnumType.AuthKit).build() + + assertEquals( + "http://localhost:${getWireMockPort()}/user_management/authorize?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fredirect&response_type=code&provider=authkit", + url + ) + } + + @Test + fun getAuthorizationUrlShouldAcceptAdditionalParams() { + val url = workos.userManagement.getAuthorizationUrl("client_id", "http://localhost:8080/redirect") + .connectionId("connection_value") + .domainHint("domain_hint") + .loginHint("login_hint") + .screenHint("screen_hint") + .provider(UserManagementProviderEnumType.AuthKit) + .state("state_value") + .build() + + assertEquals( + "http://localhost:${getWireMockPort()}/user_management/authorize?client_id=client_id&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fredirect&response_type=code&connection_id=connection_value&domain_hint=domain_hint&login_hint=login_hint&screen_hint=screen_hint&provider=authkit&state=state_value", + url + ) + } + + @Test + fun getAuthorizationUrlShouldValidateUrlParams() { + assertThrows(IllegalArgumentException::class.java) { + workos.userManagement.getAuthorizationUrl("client_id", "http://localhost:8080/redirect").build() + } + } + + @Test + fun getAuthorizationUrlShouldValidateUrlAdditionalParams() { + assertThrows(IllegalArgumentException::class.java) { + workos.userManagement.getAuthorizationUrl("client_id", "http://localhost:8080/redirect") + .connectionId("connection_value") + .domainHint("domain_hint") + .loginHint("login_hint") + .screenHint("screen_hint") + .provider(UserManagementProviderEnumType.MicrosoftOAuth) + .state("state_value") + .build() + } + } + + @Test + fun authenticateWithCodeShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456", + "access_token": "access_token", + "refresh_token": "refresh_token", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + } + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "authorization_code", + "code": "code_123", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithCode( + "client_id", + "code_123", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun authenticateWithPasswordShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456", + "access_token": "access_token", + "refresh_token": "refresh_token" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "password", + "email": "test01@example.com", + "password": "password", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithPassword( + "client_id", + "test01@example.com", + "password", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun authenticateWithMagicAuthShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "urn:workos:oauth:grant-type:magic-auth:code", + "code": "code_123", + "email": "test01@example.com", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithMagicAuth( + "client_id", + "test01@example.com", + "code_123", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun authenticateWithRefreshTokenShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "access_token": "access_token", + "refresh_token": "refresh_token" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "refresh_token", + "refresh_token": "refresh_token", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithRefreshToken( + "client_id", + "refresh_token", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals(RefreshAuthentication("access_token", "refresh_token"), response) + } + + @Test + fun authenticateWithEmailVerificationShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "urn:workos:oauth:grant-type:email-verification:code", + "code": "code_123", + "pending_authentication_token": "token_456", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithEmailVerification( + "client_id", + "code_123", + "token_456", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun authenticateWithTotpShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "urn:workos:oauth:grant-type:mfa-totp", + "code": "code_123", + "authentication_challenge_id": "challenge_789", + "pending_authentication_token": "token_456", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithTotp( + "client_id", + "code_123", + "challenge_789", + "token_456", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun authenticateWithOrganizationSelectionShouldReturnAuthenticationResponse() { + val workos = createWorkOSClient() + + stubResponse( + "/user_management/authenticate", + """{ + "user": { + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "first_name": "Test", + "last_name": "User", + "email_verified": true, + "profile_picture_url": null, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "organization_id": "org_456" + }""", + requestBody = """{ + "client_id": "client_id", + "client_secret": "apiKey", + "grant_type": "urn:workos:oauth:grant-type:organization-selection", + "organization_id": "org_123", + "pending_authentication_token": "token_456", + "ip_address": "192.0.2.1", + "user_agent": "Mozilla/5.0" + }""" + ) + + val response = workos.userManagement.authenticateWithOrganizationSelection( + "client_id", + "org_123", + "token_456", + AuthenticationAdditionalOptionsBuilder() + .ipAddress("192.0.2.1") + .userAgent("Mozilla/5.0") + .build() + ) + + assertEquals("test01@example.com", response.user?.email) + } + + @Test + fun getJwksUrlShouldReturnValidUrlResponse() { + val url = workos.userManagement.getJwksUrl("client_123") + + assertEquals( + "http://localhost:${getWireMockPort()}/sso/jwks/client_123", + url + ) + } + + @Test + fun sendMagicAuthCodeShouldWorkAndReturnNothing() { + stubResponse("/user_management/magic_auth/send", "") + + assertDoesNotThrow() { + workos.userManagement.sendMagicAuthCode("test01@example.com") + } + } + + @Test + fun enrollAuthFactorShouldReturnValidEnrolledAuthenticationFactorObject() { + stubResponse( + "/user_management/users/user_123/auth_factors", + """{ + "challenge": { + "object": "authentication_challenge", + "id": "auth_challenge_123", + "created_at": "2022-02-15T15:26:53.274Z", + "updated_at": "2022-02-15T15:26:53.274Z", + "expires_at": "2022-02-15T15:36:53.279Z", + "authentication_factor_id": "auth_factor_123" + }, + "factor": { + "object": "authentication_factor", + "id": "auth_factor_123", + "created_at": "2022-02-15T15:14:19.392Z", + "updated_at": "2022-02-15T15:14:19.392Z", + "type": "totp", + "totp": { + "issuer": "Foo Corp", + "user": "alan.turing@example.com", + "qr_code": "data:image/png;base64,{base64EncodedPng}", + "secret": "secret", + "uri": "otpauth://totp/FooCorp:alan.turing@example.com?secret=secret&issuer=FooCorp" + }, + "user_id": "user_123" + } + }""", + requestBody = """{ + "type": "totp", + "totp_issuer": "Foo Corp", + "totp_user": "test01@example.com" + }""" + ) + + val options = EnrolledAuthenticationFactorOptionsBuilder() + .totpUser("test01@example.com") + .totpIssuer("Foo Corp") + .build() + + val enrolledAuthenticationFactor = workos.userManagement.enrollAuthFactor("user_123", options) + + assertEquals( + EnrolledAuthenticationFactor( + AuthenticationChallenge( + "auth_challenge_123", + "2022-02-15T15:26:53.274Z", + "2022-02-15T15:26:53.274Z", + "2022-02-15T15:36:53.279Z", + "auth_factor_123" + ), + AuthenticationFactor( + "auth_factor_123", + "2022-02-15T15:14:19.392Z", + "2022-02-15T15:14:19.392Z", + "totp", + AuthenticationTotp( + "Foo Corp", + "alan.turing@example.com", + "data:image/png;base64,{base64EncodedPng}", + "secret", + "otpauth://totp/FooCorp:alan.turing@example.com?secret=secret&issuer=FooCorp" + ), + "user_123" + ), + ), + enrolledAuthenticationFactor + ) + } + + @Test + fun listAuthenticationFactorsShouldReturnValidAuthenticationFactors() { + stubResponse( + "/user_management/users/user_123/auth_factors", + """{ + "data": [ + { + "object": "authentication_factor", + "id": "auth_factor_123", + "created_at": "2022-02-15T15:14:19.392Z", + "updated_at": "2022-02-15T15:14:19.392Z", + "type": "totp", + "totp": { + "issuer": "Foo Corp", + "user": "alan.turing@example.com", + "qr_code": "data:image/png;base64,{base64EncodedPng}", + "secret": "secret", + "uri": "otpauth://totp/FooCorp:alan.turing@example.com?secret=secret&issuer=FooCorp" + }, + "user_id": "user_123" + } + ], + "list_metadata": { + "after": null, + "before": "auth_factor_234" + } + }""" + ) + + val authenticationFactors = workos.userManagement.listAuthFactors("user_123") + + assertEquals( + AuthenticationFactor( + "auth_factor_123", + "2022-02-15T15:14:19.392Z", + "2022-02-15T15:14:19.392Z", + "totp", + AuthenticationTotp( + "Foo Corp", + "alan.turing@example.com", + "data:image/png;base64,{base64EncodedPng}", + "secret", + "otpauth://totp/FooCorp:alan.turing@example.com?secret=secret&issuer=FooCorp" + ), + "user_123" + ), + authenticationFactors.data[0] + ) + assertEquals( + ListMetadata( + null, "auth_factor_234" + ), + authenticationFactors.listMetadata + ) + } + + @Test + fun sendPasswordResetEmailShouldWorkAndReturnNothing() { + stubResponse("/user_management/password_reset/send", "") + + assertDoesNotThrow() { + workos.userManagement.sendPasswordResetEmail("test01@example.com", "https://your-app.com/reset-password") + } + } + + @Test + fun resetPasswordShouldReturnValidUserObject() { + stubResponse( + "/user_management/password_reset/confirm", + """{ + "object": "user", + "id": "user_123", + "email": "test01@example.com", + "email_verified": true, + "profile_picture_url": null, + "first_name": "Test", + "last_name": "User", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "token": "token_123", + "new_password": "new_password" + }""" + ) + + val user = workos.userManagement.resetPassword("token_123", "new_password") + + assertEquals( + User( + "user_123", + "test01@example.com", + "Test", + "User", + true, + null, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + user + ) + } + + @Test + fun getOrganizationMembershipShouldReturnValidOrganizationMembershipObject() { + stubResponse( + "/user_management/organization_memberships/om_123", + """{ + "object": "organization_membership", + "id": "om_123", + "user_id": "user_456", + "organization_id": "org_789", + "role": { + "slug": "admin" + }, + "status": "active", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""" + ) + + val organizationMembership = workos.userManagement.getOrganizationMembership("om_123") + + assertEquals( + OrganizationMembership( + "om_123", + "user_456", + "org_789", + OrganizationMembershipRole("admin"), + OrganizationMembershipStatusEnumType.Active, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z", + ), + organizationMembership + ) + } + + @Test + fun listOrganizationMembershipsShouldReturnValidOrganizationMemberships() { + stubResponse( + "/user_management/organization_memberships", + """{ + "data": [ + { + "object": "organization_membership", + "id": "om_123", + "user_id": "user_456", + "organization_id": "org_789", + "role": { + "slug": "admin" + }, + "status": "active", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "om_234" + } + }""" + ) + + val organizationMemberships = workos.userManagement.listOrganizationMemberships(ListOrganizationMembershipsOptionsBuilder().build()) + + assertEquals( + OrganizationMembership( + "om_123", + "user_456", + "org_789", + OrganizationMembershipRole("admin"), + OrganizationMembershipStatusEnumType.Active, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z", + ), + organizationMemberships.data[0] + ) + assertEquals( + ListMetadata( + null, "om_234" + ), + organizationMemberships.listMetadata + ) + } + + @Test + fun listOrganizationMembershipsShouldReturnValidOrganizationMembershipsWithPaginationAndFilters() { + stubResponse( + "/user_management/organization_memberships", + """{ + "data": [ + { + "object": "organization_membership", + "id": "om_123", + "user_id": "user_456", + "organization_id": "org_789", + "role": { + "slug": "admin" + }, + "status": "active", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "om_234" + } + }""" + ) + + val options = ListOrganizationMembershipsOptionsBuilder() + .userId("id_456") + .organizationId("org_789") + .order(Order.Desc) + .limit(10) + .after("someAfterId") + .before("someBeforeId") + .build() + + val organizationMemberships = workos.userManagement.listOrganizationMemberships(options) + + assertEquals( + OrganizationMembership( + "om_123", + "user_456", + "org_789", + OrganizationMembershipRole("admin"), + OrganizationMembershipStatusEnumType.Active, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z", + ), + organizationMemberships.data[0] + ) + assertEquals( + ListMetadata( + null, "om_234" + ), + organizationMemberships.listMetadata + ) + } + + @Test + fun createOrganizationMembershipShouldReturnValidOrganizationMembershipObject() { + stubResponse( + "/user_management/organization_memberships", + """{ + "object": "organization_membership", + "id": "om_123", + "user_id": "user_456", + "organization_id": "org_789", + "role": { + "slug": "admin" + }, + "status": "active", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "user_id": "user_456", + "organization_id": "org_789", + "role_slug": "admin" + }""" + ) + + val options = CreateOrganizationMembershipOptionsBuilder("user_456", "org_789") + .roleSlug("admin") + .build() + + val organizationMembership = workos.userManagement.createOrganizationMembership(options) + + assertEquals( + OrganizationMembership( + "om_123", + "user_456", + "org_789", + OrganizationMembershipRole("admin"), + OrganizationMembershipStatusEnumType.Active, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z", + ), + organizationMembership + ) + } + + @Test + fun updateOrganizationMembershipShouldReturnValidOrganizationMembershipObject() { + stubResponse( + "/user_management/organization_memberships/om_123", + """{ + "object": "organization_membership", + "id": "om_123", + "user_id": "user_456", + "organization_id": "org_789", + "role": { + "slug": "member" + }, + "status": "active", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "id": "om_123", + "role_slug": "member" + }""" + ) + + val organizationMembership = workos.userManagement.updateOrganizationMembership("om_123", "member") + + assertEquals( + OrganizationMembership( + "om_123", + "user_456", + "org_789", + OrganizationMembershipRole("member"), + OrganizationMembershipStatusEnumType.Active, + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z", + ), + organizationMembership + ) + } + + @Test + fun deleteOrganizationMembershipShouldWorkAndReturnNothing() { + stubResponse("/user_management/organization_memberships/om_123", "") + + assertDoesNotThrow() { + workos.userManagement.deleteOrganizationMembership("om_123") + } + } + + @Test + fun getInvitationShouldReturnValidUserObject() { + stubResponse( + "/user_management/invitations/invitation_123", + """{ + "id": "invitation_123", + "email": "test01@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2021-07-01T19:07:33.155Z", + "token": "token", + "organization_id": "org_456", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""" + ) + + val invitation = workos.userManagement.getInvitation("invitation_123") + + assertEquals( + Invitation( + "invitation_123", + "test01@example.com", + InvitationStateEnumType.Pending, + null, + null, + "2021-07-01T19:07:33.155Z", + "token", + "org_456", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + invitation + ) + } + + @Test + fun listInvitationsShouldReturnValidInvitations() { + stubResponse( + "/user_management/invitations", + """{ + "data": [ + { + "id": "invitation_123", + "email": "test01@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2021-07-01T19:07:33.155Z", + "token": "token", + "organization_id": "org_456", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "invitation_234" + } + }""" + ) + + val invitations = workos.userManagement.listInvitations(ListInvitationsOptionsBuilder().build()) + + assertEquals( + Invitation( + "invitation_123", + "test01@example.com", + InvitationStateEnumType.Pending, + null, + null, + "2021-07-01T19:07:33.155Z", + "token", + "org_456", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + invitations.data[0] + ) + assertEquals( + ListMetadata( + null, "invitation_234" + ), + invitations.listMetadata + ) + } + + @Test + fun listInvitationsShouldReturnValidInvitationsWithPaginationAndFilters() { + stubResponse( + "/user_management/invitations", + """{ + "data": [ + { + "id": "invitation_123", + "email": "test01@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2021-07-01T19:07:33.155Z", + "token": "token", + "organization_id": "org_456", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + } + ], + "list_metadata": { + "after": null, + "before": "invitation_234" + } + }""" + ) + + val options = ListInvitationsOptionsBuilder() + .email("test01@example.com") + .organizationId("org_123") + .order(Order.Desc) + .limit(10) + .after("someAfterId") + .before("someBeforeId") + .build() + + val invitations = workos.userManagement.listInvitations(options) + + assertEquals( + Invitation( + "invitation_123", + "test01@example.com", + InvitationStateEnumType.Pending, + null, + null, + "2021-07-01T19:07:33.155Z", + "token", + "org_456", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + invitations.data[0] + ) + assertEquals( + ListMetadata( + null, "invitation_234" + ), + invitations.listMetadata + ) + } + + @Test + fun sendInvitationShouldReturnValidInvitationObject() { + stubResponse( + "/user_management/invitations", + """{ + "id": "invitation_123", + "email": "test01@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2021-07-01T19:07:33.155Z", + "token": "token", + "organization_id": "org_456", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""", + requestBody = """{ + "email": "test01@example.com", + "organization_id": "org_456", + "expires_in_days": 10, + "inviter_user_id": "user_789", + "role_slug": "admin" + }""" + ) + + val options = SendInvitationOptionsBuilder("test01@example.com") + .organizationId("org_456") + .expiresInDays(10) + .inviterUserId("user_789") + .roleSlug("admin") + .build() + + val invitation = workos.userManagement.sendInvitation(options) + + assertEquals( + Invitation( + "invitation_123", + "test01@example.com", + InvitationStateEnumType.Pending, + null, + null, + "2021-07-01T19:07:33.155Z", + "token", + "org_456", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + invitation + ) + } + + @Test + fun deleteInvitationShouldWorkAndReturnNothing() { + stubResponse( + "/user_management/invitations/invitation_123/revoke", + """{ + "id": "invitation_123", + "email": "test01@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": "2021-08-01T19:07:33.155Z", + "expires_at": "2021-07-01T19:07:33.155Z", + "token": "token", + "organization_id": "org_456", + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }""" + ) + + val invitation = workos.userManagement.revokeInvitation("invitation_123") + + assertEquals( + Invitation( + "invitation_123", + "test01@example.com", + InvitationStateEnumType.Pending, + null, + "2021-08-01T19:07:33.155Z", + "2021-07-01T19:07:33.155Z", + "token", + "org_456", + "2021-06-25T19:07:33.155Z", + "2021-06-25T19:07:33.155Z" + ), + invitation + ) + } + + @Test + fun getLogoutUrlShouldReturnValidUrlResponse() { + val url = workos.userManagement.getLogoutUrl("session_123") + + assertEquals( + "http://localhost:${getWireMockPort()}/user_management/sessions/logout?session_id=session_123", + url + ) + } +}