Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [Step 1: Issue an OTP challenge](#step-1-issue-an-otp-challenge)
- [Step 2: Verify the code and log in](#step-2-verify-the-code-and-log-in)
- [Sign Up with a database connection](#sign-up-with-a-database-connection)
- [Reset a password](#reset-a-password)
- [Get user information](#get-user-information)
- [Custom Token Exchange](#custom-token-exchange)
- [Custom Token Exchange with Actor Token (Delegation/Impersonation)](#custom-token-exchange-with-actor-token-delegationimpersonation)
Expand Down Expand Up @@ -1786,6 +1787,69 @@ authentication

> The default scope used is `openid profile email`. Regardless of the scopes set to the request, the `openid` scope is always enforced.

### Reset a password

Send a password reset email to a database user.

```kotlin
authentication
.resetPassword("info@auth0.com", "my-database-connection")
.start(object: Callback<Void?, AuthenticationException> {
override fun onFailure(exception: AuthenticationException) { }

override fun onSuccess(result: Void?) { }
})
```

If the user belongs to an [organization](#organizations), pass its identifier to associate the reset request with that organization. Auth0 then includes the `organization_id` and `organization_name` values in the password reset redirect URL, and makes them available as variables in customized email templates.

```kotlin
authentication
.resetPassword("info@auth0.com", "my-database-connection", "org_abc123")
.start(object: Callback<Void?, AuthenticationException> {
override fun onFailure(exception: AuthenticationException) { }

override fun onSuccess(result: Void?) { }
})
```

<details>
<summary>Using coroutines</summary>

```kotlin
try {
authentication
.resetPassword("info@auth0.com", "my-database-connection", "org_abc123")
.await()
println("Password reset email sent")
} catch (e: AuthenticationException) {
e.printStacktrace()
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
```
</details>

<details>
<summary>Using Java</summary>

```java
authentication
.resetPassword("info@auth0.com", "my-database-connection", "org_abc123")
.start(new Callback<Void, AuthenticationException>() {
@Override
public void onSuccess(@Nullable Void payload) {
//Password reset email sent!
}

@Override
public void onFailure(@NonNull AuthenticationException error) {
//Error!
}
});
```
</details>

> The `organization` parameter must be the organization ID (for example, `org_abc123`), not the organization name. It is optional — omit it to send a password reset that is not associated with an organization.

### Get user information

```kotlin
Expand Down Expand Up @@ -3656,6 +3720,8 @@ client
[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.
Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans.

Besides Web Auth login, the Authentication API client can also associate a password reset request with an organization. See [Reset a password](#reset-a-password).

### Log in to an organization

```kotlin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* Example usage:
*
* ```
* client.resetPassword("{email}", "{database connection name}")
* client.resetPassword("{email}", "{database connection name}", "{organization}")
* .start(object: Callback<Void?, AuthenticationException> {
* override fun onSuccess(result: Void?) { }
* override fun onFailure(error: AuthenticationException) { }
Expand All @@ -615,21 +615,27 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
*
* @param email of the user to request the password reset. An email will be sent with the reset instructions.
* @param connection of the database to request the reset password on
* @param organization id of the organization the user belongs to. When set, Auth0 associates the password
* reset request with this organization, making the organization details available in the reset redirect URL
* and in customized email templates. Must be the organization id, not the organization name.
* @return a request to configure and start
*/
@JvmOverloads
public fun resetPassword(
email: String,
connection: String
connection: String,
organization: String? = null
Comment thread
NandanPrabhu marked this conversation as resolved.
Resolved
): Request<Void?, AuthenticationException> {
val url = auth0.getDomainUrl().toHttpUrl().newBuilder()
.addPathSegment(DB_CONNECTIONS_PATH)
.addPathSegment(CHANGE_PASSWORD_PATH)
.build()
val parameters = ParameterBuilder.newBuilder()
.set(EMAIL_KEY, email)
.setClientId(clientId)
.setConnection(connection)
.asDictionary()
val parameters = ParameterBuilder.newBuilder().apply {
set(EMAIL_KEY, email)
setClientId(clientId)
setConnection(connection)
organization?.let { set(ORGANIZATION_KEY, it) }
}.asDictionary()
return factory.post(url.toString())
.addParameters(parameters)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,89 @@ public class AuthenticationAPIClientTest {
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
}

@Test
public fun shouldChangePasswordWithOrganization() {
mockAPI.willReturnSuccessfulChangePassword()
val callback = MockAuthenticationCallback<Void>()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION, "org_12345")
.start(callback)
ShadowLooper.idleMainLooper()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
assertThat(body, Matchers.hasEntry("organization", "org_12345"))
assertThat(callback, AuthenticationCallbackMatcher.hasNoError())
}

@Test
public fun shouldChangePasswordWithOrganizationSync() {
mockAPI.willReturnSuccessfulChangePassword()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION, "org_12345")
.execute()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.hasEntry("organization", "org_12345"))
}

@Test
@ExperimentalCoroutinesApi
public fun shouldAwaitChangePasswordWithOrganization(): Unit = runTest {
mockAPI.willReturnSuccessfulChangePassword()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION, "org_12345")
.await()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.hasEntry("organization", "org_12345"))
}

@Test
public fun shouldNotSendOrganizationOnChangePasswordWhenNull() {
mockAPI.willReturnSuccessfulChangePassword()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION, null)
.execute()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.not(Matchers.hasKey("organization")))
}

@Test
public fun shouldNotSendOrganizationOnChangePasswordWhenNotProvided() {
mockAPI.willReturnSuccessfulChangePassword()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION)
.execute()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.not(Matchers.hasKey("organization")))
}

@Test
public fun shouldSendEmptyOrganizationOnChangePasswordWithoutValidating() {
mockAPI.willReturnSuccessfulChangePassword()
client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION, "")
.execute()
val request = mockAPI.takeRequest()
assertThat(request.path, Matchers.equalTo("/dbconnections/change_password"))
val body = bodyFromRequest<String>(request)
assertThat(body, Matchers.hasEntry("email", SUPPORT_AUTH0_COM))
assertThat(body, Matchers.hasEntry("connection", MY_CONNECTION))
assertThat(body, Matchers.hasEntry("organization", ""))
}

@Test
public fun shouldSendEmailCodeWithCustomConnection() {
mockAPI.willReturnSuccessfulPasswordlessStart()
Expand Down
Loading