Skip to content

Commit ec07c95

Browse files
authored
feat(auth): add resend method (#190)
1 parent 7ec9d60 commit ec07c95

File tree

5 files changed

+135
-0
lines changed

5 files changed

+135
-0
lines changed

Sources/Auth/AuthClient.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,70 @@ public actor AuthClient {
689689
return response
690690
}
691691

692+
/// Resends an existing signup confirmation email or email change email.
693+
///
694+
/// To obfuscate whether such the email already exists in the system this method succeeds in both
695+
/// cases.
696+
public func resend(
697+
email: String,
698+
type: ResendEmailType,
699+
emailRedirectTo: URL? = nil,
700+
captchaToken: String? = nil
701+
) async throws {
702+
if type != .emailChange {
703+
await sessionManager.remove()
704+
}
705+
706+
_ = try await api.execute(
707+
Request(
708+
path: "/resend",
709+
method: .post,
710+
query: [
711+
emailRedirectTo.map { URLQueryItem(name: "redirect_to", value: $0.absoluteString) },
712+
].compactMap { $0 },
713+
body: configuration.encoder.encode(
714+
ResendEmailParams(
715+
type: type,
716+
email: email,
717+
gotrueMetaSecurity: captchaToken.map(AuthMetaSecurity.init(captchaToken:))
718+
)
719+
)
720+
)
721+
)
722+
}
723+
724+
/// Resends an existing SMS OTP or phone change OTP.
725+
/// - Returns: An object containing the unique ID of the message as reported by the SMS sending
726+
/// provider. Useful for tracking deliverability problems.
727+
///
728+
/// To obfuscate whether such the phone number already exists in the system this method succeeds
729+
/// in both cases.
730+
@discardableResult
731+
public func resend(
732+
phone: String,
733+
type: ResendMobileType,
734+
captchaToken: String? = nil
735+
) async throws -> ResendMobileResponse {
736+
if type != .phoneChange {
737+
await sessionManager.remove()
738+
}
739+
740+
return try await api.execute(
741+
Request(
742+
path: "/resend",
743+
method: .post,
744+
body: configuration.encoder.encode(
745+
ResendMobileParams(
746+
type: type,
747+
phone: phone,
748+
gotrueMetaSecurity: captchaToken.map(AuthMetaSecurity.init(captchaToken:))
749+
)
750+
)
751+
)
752+
)
753+
.decoded(decoder: configuration.decoder)
754+
}
755+
692756
/// Gets the current user details if there is an existing session.
693757
/// - Parameter jwt: Takes in an optional access token jwt. If no jwt is provided, user() will
694758
/// attempt to get the jwt from the current session.

Sources/Auth/Types.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,3 +586,35 @@ public enum SignOutScope: String, Sendable {
586586
/// session.
587587
case others
588588
}
589+
590+
public enum ResendEmailType: String, Hashable, Sendable, Encodable {
591+
case signup
592+
case emailChange = "email_change"
593+
}
594+
595+
struct ResendEmailParams: Encodable {
596+
let type: ResendEmailType
597+
let email: String
598+
let gotrueMetaSecurity: AuthMetaSecurity?
599+
}
600+
601+
public enum ResendMobileType: String, Hashable, Sendable, Encodable {
602+
case sms
603+
case phoneChange = "phone_change"
604+
}
605+
606+
struct ResendMobileParams: Encodable {
607+
let type: ResendMobileType
608+
let phone: String
609+
let gotrueMetaSecurity: AuthMetaSecurity?
610+
}
611+
612+
public struct ResendMobileResponse: Decodable, Hashable, Sendable {
613+
/// Unique ID of the message as reported by the SMS sending provider. Useful for tracking
614+
/// deliverability problems.
615+
public let messageId: String?
616+
617+
public init(messageId: String?) {
618+
self.messageId = messageId
619+
}
620+
}

Tests/AuthTests/RequestsTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,31 @@ final class RequestsTests: XCTestCase {
344344
}
345345
}
346346

347+
func testResendEmail() async {
348+
let sut = makeSUT()
349+
350+
await assert {
351+
try await sut.resend(
352+
353+
type: .emailChange,
354+
emailRedirectTo: URL(string: "https://supabase.com"),
355+
captchaToken: "captcha-token"
356+
)
357+
}
358+
}
359+
360+
func testResendPhone() async {
361+
let sut = makeSUT()
362+
363+
await assert {
364+
try await sut.resend(
365+
phone: "+1 202-918-2132",
366+
type: .phoneChange,
367+
captchaToken: "captcha-token"
368+
)
369+
}
370+
}
371+
347372
private func assert(_ block: () async throws -> Void) async {
348373
do {
349374
try await block()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
curl \
2+
--request POST \
3+
--header "Content-Type: application/json" \
4+
--header "X-Client-Info: gotrue-swift/x.y.z" \
5+
--header "apikey: dummy.api.key" \
6+
--data "{\"email\":\"[email protected]\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"type\":\"email_change\"}" \
7+
"http://localhost:54321/auth/v1/resend?redirect_to=https://supabase.com"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
curl \
2+
--request POST \
3+
--header "Content-Type: application/json" \
4+
--header "X-Client-Info: gotrue-swift/x.y.z" \
5+
--header "apikey: dummy.api.key" \
6+
--data "{\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"phone\":\"+1 202-918-2132\",\"type\":\"phone_change\"}" \
7+
"http://localhost:54321/auth/v1/resend"

0 commit comments

Comments
 (0)