Skip to content

Commit fa8db0c

Browse files
authored
chore(docs): add phone sign in example (#522)
1 parent d44fb8a commit fa8db0c

File tree

6 files changed

+161
-16
lines changed

6 files changed

+161
-16
lines changed

Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
797EFB6C2BABE1B800098D6B /* FileObjectDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EFB6B2BABE1B800098D6B /* FileObjectDetailView.swift */; };
3838
7993B8A92B3C673A009B610B /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993B8A82B3C673A009B610B /* AuthView.swift */; };
3939
7993B8AB2B3C67E0009B610B /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7993B8AA2B3C67E0009B610B /* Toast.swift */; };
40+
799EE6A32C877BFB00FD9DD7 /* SignInWithPhone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799EE6A22C877BF900FD9DD7 /* SignInWithPhone.swift */; };
4041
79AF047F2B2CE207008761AD /* AuthWithEmailAndPassword.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79AF047E2B2CE207008761AD /* AuthWithEmailAndPassword.swift */; };
4142
79AF04812B2CE261008761AD /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79AF04802B2CE261008761AD /* AuthView.swift */; };
4243
79AF04842B2CE408008761AD /* AuthWithMagicLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79AF04832B2CE408008761AD /* AuthWithMagicLink.swift */; };
@@ -106,6 +107,7 @@
106107
7993B8A82B3C673A009B610B /* AuthView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthView.swift; sourceTree = "<group>"; };
107108
7993B8AA2B3C67E0009B610B /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
108109
7993B8AC2B3C97B6009B610B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
110+
799EE6A22C877BF900FD9DD7 /* SignInWithPhone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInWithPhone.swift; sourceTree = "<group>"; };
109111
79AF047E2B2CE207008761AD /* AuthWithEmailAndPassword.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthWithEmailAndPassword.swift; sourceTree = "<group>"; };
110112
79AF04802B2CE261008761AD /* AuthView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthView.swift; sourceTree = "<group>"; };
111113
79AF04832B2CE408008761AD /* AuthWithMagicLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthWithMagicLink.swift; sourceTree = "<group>"; };
@@ -258,6 +260,7 @@
258260
79AF04822B2CE3BD008761AD /* Auth */ = {
259261
isa = PBXGroup;
260262
children = (
263+
799EE6A22C877BF900FD9DD7 /* SignInWithPhone.swift */,
261264
7956405F2954AE140088A06F /* AuthController.swift */,
262265
79AF04802B2CE261008761AD /* AuthView.swift */,
263266
79AF047E2B2CE207008761AD /* AuthWithEmailAndPassword.swift */,
@@ -490,6 +493,7 @@
490493
buildActionMask = 2147483647;
491494
files = (
492495
796298992AEBBA77000AA957 /* MFAFlow.swift in Sources */,
496+
799EE6A32C877BFB00FD9DD7 /* SignInWithPhone.swift in Sources */,
493497
79AF04862B2CE586008761AD /* Debug.swift in Sources */,
494498
79AF04842B2CE408008761AD /* AuthWithMagicLink.swift in Sources */,
495499
79401F352BC708C8004C9C0F /* UIViewControllerWrapper.swift in Sources */,

Examples/Examples/Auth/AuthController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ final class AuthController {
2626

2727
init() {
2828
observeAuthStateChangesTask = Task {
29-
for await (event, session) in await supabase.auth.authStateChanges {
29+
for await (event, session) in supabase.auth.authStateChanges {
3030
guard [.initialSession, .signedIn, .signedOut].contains(event) else { return }
3131

3232
self.session = session

Examples/Examples/Auth/AuthView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct AuthView: View {
1111
enum Option: CaseIterable {
1212
case emailAndPassword
1313
case magicLink
14+
case signInWithPhone
1415
case signInWithApple
1516
case signInWithOAuth
1617
case signInWithOAuthUsingUIKit
@@ -21,6 +22,7 @@ struct AuthView: View {
2122
switch self {
2223
case .emailAndPassword: "Auth with Email & Password"
2324
case .magicLink: "Auth with Magic Link"
25+
case .signInWithPhone: "Sign in with Phone"
2426
case .signInWithApple: "Sign in with Apple"
2527
case .signInWithOAuth: "Sign in with OAuth flow"
2628
case .signInWithOAuthUsingUIKit: "Sign in with OAuth flow (UIKit)"
@@ -51,6 +53,7 @@ extension AuthView.Option: View {
5153
switch self {
5254
case .emailAndPassword: AuthWithEmailAndPassword()
5355
case .magicLink: AuthWithMagicLink()
56+
case .signInWithPhone: SignInWithPhone()
5457
case .signInWithApple: SignInWithApple()
5558
case .signInWithOAuth: SignInWithOAuth()
5659
case .signInWithOAuthUsingUIKit: UIViewControllerWrapper(SignInWithOAuthViewController())
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//
2+
// SignInWithPhone.swift
3+
// Examples
4+
//
5+
// Created by Guilherme Souza on 03/09/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct SignInWithPhone: View {
11+
@State var phone = ""
12+
@State var code = ""
13+
14+
@State var actionState: ActionState<Void, Error> = .idle
15+
@State var verifyActionState: ActionState<Void, Error> = .idle
16+
17+
@State var isVerifyStep = false
18+
19+
var body: some View {
20+
if isVerifyStep {
21+
VStack {
22+
verifyView
23+
Button("Change phone") {
24+
isVerifyStep = false
25+
}
26+
}
27+
} else {
28+
phoneView
29+
}
30+
}
31+
32+
var phoneView: some View {
33+
Form {
34+
Section {
35+
TextField("Phone", text: $phone)
36+
.keyboardType(.phonePad)
37+
.textContentType(.telephoneNumber)
38+
.autocorrectionDisabled()
39+
.textInputAutocapitalization(.never)
40+
}
41+
42+
Section {
43+
Button("Send code to number") {
44+
Task {
45+
await sendCodeToNumberTapped()
46+
}
47+
}
48+
}
49+
50+
switch actionState {
51+
case .idle, .result(.success):
52+
EmptyView()
53+
case .inFlight:
54+
ProgressView()
55+
case let .result(.failure(error)):
56+
ErrorText(error)
57+
}
58+
}
59+
}
60+
61+
var verifyView: some View {
62+
Form {
63+
Section {
64+
TextField("Code", text: $code)
65+
.keyboardType(.numberPad)
66+
.textContentType(.oneTimeCode)
67+
.autocorrectionDisabled()
68+
.textInputAutocapitalization(.never)
69+
}
70+
71+
Section {
72+
Button("Verify") {
73+
Task {
74+
await verifyButtonTapped()
75+
}
76+
}
77+
}
78+
79+
switch verifyActionState {
80+
case .idle, .result(.success):
81+
EmptyView()
82+
case .inFlight:
83+
ProgressView()
84+
case let .result(.failure(error)):
85+
ErrorText(error)
86+
}
87+
}
88+
}
89+
90+
private func sendCodeToNumberTapped() async {
91+
actionState = .inFlight
92+
93+
do {
94+
try await supabase.auth.signInWithOTP(phone: phone)
95+
actionState = .result(.success(()))
96+
isVerifyStep = true
97+
} catch {
98+
actionState = .result(.failure(error))
99+
}
100+
}
101+
102+
private func verifyButtonTapped() async {
103+
verifyActionState = .inFlight
104+
do {
105+
try await supabase.auth.verifyOTP(phone: phone, token: code, type: .sms)
106+
verifyActionState = .result(.success(()))
107+
} catch {
108+
verifyActionState = .result(.failure(error))
109+
}
110+
}
111+
}
112+
113+
#Preview {
114+
SignInWithPhone()
115+
}

Examples/supabase/config.toml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ double_confirm_changes = true
6464
# If enabled, users need to confirm their email address before signing in.
6565
enable_confirmations = false
6666

67+
[auth.sms]
68+
# Allow/disallow new user signups via SMS to your project.
69+
enable_signup = true
70+
# If enabled, users need to confirm their phone number before signing in.
71+
enable_confirmations = false
72+
# Template for sending OTP to users
73+
template = "Your code is {{ `{{ .Code }}` }} ."
74+
# Controls the minimum amount of time that must pass before sending another sms otp.
75+
max_frequency = "5s"
76+
77+
# Use pre-defined map of phone number to OTP for testing.
78+
[auth.sms.test_otp]
79+
4152127777 = "123456"
80+
81+
82+
# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
83+
[auth.sms.twilio]
84+
enabled = true
85+
account_sid = "account sid"
86+
message_service_sid = "account service sid"
87+
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
88+
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
89+
6790
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
6891
# `discord`, `facebook`, `github`, `gitlab`, `google`, `twitch`, `twitter`, `slack`, `spotify`.
6992
[auth.external.apple]
@@ -80,4 +103,4 @@ url = ""
80103
[auth.external.github]
81104
enabled = false
82105
client_id = "12d1131cd3582f942c71"
83-
secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"
106+
secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"

Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)