Skip to content

Commit 1290bcf

Browse files
authored
feat(auth): add signInWithOAuth (#299)
1 parent 3b74720 commit 1290bcf

File tree

14 files changed

+468
-102
lines changed

14 files changed

+468
-102
lines changed

Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
793E03092B2CED5D00AC7DED /* Contants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793E03082B2CED5D00AC7DED /* Contants.swift */; };
1515
793E030B2B2CEDDA00AC7DED /* ActionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793E030A2B2CEDDA00AC7DED /* ActionState.swift */; };
1616
793E030D2B2DAB5700AC7DED /* SignInWithApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793E030C2B2DAB5700AC7DED /* SignInWithApple.swift */; };
17-
7940E3152B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7940E3142B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift */; };
17+
79401F332BC6FEAE004C9C0F /* SignInWithOAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79401F322BC6FEAE004C9C0F /* SignInWithOAuth.swift */; };
18+
79401F352BC708C8004C9C0F /* UIViewControllerWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79401F342BC708C8004C9C0F /* UIViewControllerWrapper.swift */; };
1819
794C61D62BAD1E12000E6B0F /* UserIdentityList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794C61D52BAD1E12000E6B0F /* UserIdentityList.swift */; };
1920
794EF1222955F26A008C9526 /* AddTodoListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794EF1212955F26A008C9526 /* AddTodoListView.swift */; };
2021
794EF1242955F3DE008C9526 /* TodoListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 794EF1232955F3DE008C9526 /* TodoListRow.swift */; };
@@ -83,7 +84,8 @@
8384
793E03082B2CED5D00AC7DED /* Contants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contants.swift; sourceTree = "<group>"; };
8485
793E030A2B2CEDDA00AC7DED /* ActionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionState.swift; sourceTree = "<group>"; };
8586
793E030C2B2DAB5700AC7DED /* SignInWithApple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInWithApple.swift; sourceTree = "<group>"; };
86-
7940E3142B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleSignInWithWebFlow.swift; sourceTree = "<group>"; };
87+
79401F322BC6FEAE004C9C0F /* SignInWithOAuth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInWithOAuth.swift; sourceTree = "<group>"; };
88+
79401F342BC708C8004C9C0F /* UIViewControllerWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerWrapper.swift; sourceTree = "<group>"; };
8789
794C61D52BAD1E12000E6B0F /* UserIdentityList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIdentityList.swift; sourceTree = "<group>"; };
8890
794EF1212955F26A008C9526 /* AddTodoListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTodoListView.swift; sourceTree = "<group>"; };
8991
794EF1232955F3DE008C9526 /* TodoListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoListRow.swift; sourceTree = "<group>"; };
@@ -221,6 +223,7 @@
221223
79E2B55B2B97A2310042CD21 /* UIApplicationExtensions.swift */,
222224
797EFB672BABD90500098D6B /* Stringfy.swift */,
223225
79B1C80D2BAC017C00D991AA /* AnyJSONView.swift */,
226+
79401F342BC708C8004C9C0F /* UIViewControllerWrapper.swift */,
224227
);
225228
path = Examples;
226229
sourceTree = "<group>";
@@ -258,9 +261,9 @@
258261
79AF047E2B2CE207008761AD /* AuthWithEmailAndPassword.swift */,
259262
79AF04832B2CE408008761AD /* AuthWithMagicLink.swift */,
260263
793E030C2B2DAB5700AC7DED /* SignInWithApple.swift */,
261-
7940E3142B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift */,
262264
79E2B5542B9788BF0042CD21 /* GoogleSignInSDKFlow.swift */,
263265
79C9B8E42BBB16C0003AD942 /* SignInAnonymously.swift */,
266+
79401F322BC6FEAE004C9C0F /* SignInWithOAuth.swift */,
264267
);
265268
path = Auth;
266269
sourceTree = "<group>";
@@ -486,6 +489,8 @@
486489
796298992AEBBA77000AA957 /* MFAFlow.swift in Sources */,
487490
79AF04862B2CE586008761AD /* Debug.swift in Sources */,
488491
79AF04842B2CE408008761AD /* AuthWithMagicLink.swift in Sources */,
492+
79401F352BC708C8004C9C0F /* UIViewControllerWrapper.swift in Sources */,
493+
79401F332BC6FEAE004C9C0F /* SignInWithOAuth.swift in Sources */,
489494
79B1C80E2BAC017C00D991AA /* AnyJSONView.swift in Sources */,
490495
79E2B5552B9788BF0042CD21 /* GoogleSignInSDKFlow.swift in Sources */,
491496
793E03092B2CED5D00AC7DED /* Contants.swift in Sources */,
@@ -504,7 +509,6 @@
504509
795640602954AE140088A06F /* AuthController.swift in Sources */,
505510
79AF047F2B2CE207008761AD /* AuthWithEmailAndPassword.swift in Sources */,
506511
795640622955AD2B0088A06F /* HomeView.swift in Sources */,
507-
7940E3152B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift in Sources */,
508512
793895CA2954ABFF0044F2B8 /* ExamplesApp.swift in Sources */,
509513
797EFB682BABD90500098D6B /* Stringfy.swift in Sources */,
510514
797EFB6C2BABE1B800098D6B /* FileObjectDetailView.swift in Sources */,

Examples/Examples/Auth/AuthView.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ struct AuthView: View {
1212
case emailAndPassword
1313
case magicLink
1414
case signInWithApple
15-
case googleSignInWebFlow
15+
case signInWithOAuth
16+
case signInWithOAuthUsingUIKit
1617
case googleSignInSDKFlow
1718
case signInAnonymously
1819

@@ -21,7 +22,8 @@ struct AuthView: View {
2122
case .emailAndPassword: "Auth with Email & Password"
2223
case .magicLink: "Auth with Magic Link"
2324
case .signInWithApple: "Sign in with Apple"
24-
case .googleSignInWebFlow: "Google Sign in (Web Flow)"
25+
case .signInWithOAuth: "Sign in with OAuth flow"
26+
case .signInWithOAuthUsingUIKit: "Sign in with OAuth flow (UIKit)"
2527
case .googleSignInSDKFlow: "Google Sign in (GIDSignIn SDK Flow)"
2628
case .signInAnonymously: "Sign in Anonymously"
2729
}
@@ -50,7 +52,9 @@ extension AuthView.Option: View {
5052
case .emailAndPassword: AuthWithEmailAndPassword()
5153
case .magicLink: AuthWithMagicLink()
5254
case .signInWithApple: SignInWithApple()
53-
case .googleSignInWebFlow: GoogleSignInWithWebFlow()
55+
case .signInWithOAuth: SignInWithOAuth()
56+
case .signInWithOAuthUsingUIKit: UIViewControllerWrapper(SignInWithOAuthViewController())
57+
.edgesIgnoringSafeArea(.all)
5458
case .googleSignInSDKFlow: GoogleSignInSDKFlow()
5559
case .signInAnonymously: SignInAnonymously()
5660
}

Examples/Examples/Auth/GoogleSignInWithWebFlow.swift

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//
2+
// SignInWithOAuth.swift
3+
// Examples
4+
//
5+
// Created by Guilherme Souza on 10/04/24.
6+
//
7+
8+
import AuthenticationServices
9+
import Supabase
10+
import SwiftUI
11+
12+
struct SignInWithOAuth: View {
13+
let providers = Provider.allCases
14+
15+
@State var provider = Provider.allCases[0]
16+
@Environment(\.webAuthenticationSession) var webAuthenticationSession
17+
18+
var body: some View {
19+
VStack {
20+
Picker("Provider", selection: $provider) {
21+
ForEach(providers) { provider in
22+
Text("\(provider)").tag(provider)
23+
}
24+
}
25+
26+
Button("Start Sign-in Flow") {
27+
Task {
28+
do {
29+
try await supabase.auth.signInWithOAuth(
30+
provider: provider,
31+
redirectTo: Constants.redirectToURL,
32+
launchFlow: { @MainActor url in
33+
try await webAuthenticationSession.authenticate(
34+
using: url,
35+
callbackURLScheme: Constants.redirectToURL.scheme!
36+
)
37+
}
38+
)
39+
} catch {
40+
debug("Failed to sign-in with OAuth flow: \(error)")
41+
}
42+
}
43+
}
44+
}
45+
}
46+
}
47+
48+
final class SignInWithOAuthViewController: UIViewController, UIPickerViewDataSource,
49+
UIPickerViewDelegate
50+
{
51+
let providers = Provider.allCases
52+
var provider = Provider.allCases[0]
53+
54+
let providerPicker = UIPickerView()
55+
let signInButton = UIButton(type: .system)
56+
57+
override func viewDidLoad() {
58+
super.viewDidLoad()
59+
setupViews()
60+
}
61+
62+
func setupViews() {
63+
view.backgroundColor = .white
64+
65+
providerPicker.dataSource = self
66+
providerPicker.delegate = self
67+
view.addSubview(providerPicker)
68+
providerPicker.translatesAutoresizingMaskIntoConstraints = false
69+
NSLayoutConstraint.activate([
70+
providerPicker.centerXAnchor.constraint(equalTo: view.centerXAnchor),
71+
providerPicker.centerYAnchor.constraint(equalTo: view.centerYAnchor),
72+
providerPicker.widthAnchor.constraint(equalToConstant: 200),
73+
providerPicker.heightAnchor.constraint(equalToConstant: 100),
74+
])
75+
76+
signInButton.setTitle("Start Sign-in Flow", for: .normal)
77+
signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)
78+
view.addSubview(signInButton)
79+
signInButton.translatesAutoresizingMaskIntoConstraints = false
80+
NSLayoutConstraint.activate([
81+
signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
82+
signInButton.topAnchor.constraint(equalTo: providerPicker.bottomAnchor, constant: 20),
83+
])
84+
}
85+
86+
@objc func signInButtonTapped() {
87+
Task {
88+
do {
89+
try await supabase.auth.signInWithOAuth(
90+
provider: provider,
91+
redirectTo: Constants.redirectToURL
92+
)
93+
} catch {
94+
debug("Failed to sign-in with OAuth flow: \(error)")
95+
}
96+
}
97+
}
98+
99+
func numberOfComponents(in _: UIPickerView) -> Int {
100+
1
101+
}
102+
103+
func pickerView(_: UIPickerView, numberOfRowsInComponent _: Int) -> Int {
104+
providers.count
105+
}
106+
107+
func pickerView(_: UIPickerView, titleForRow row: Int, forComponent _: Int) -> String? {
108+
"\(providers[row])"
109+
}
110+
111+
func pickerView(_: UIPickerView, didSelectRow row: Int, inComponent _: Int) {
112+
provider = providers[row]
113+
}
114+
}
115+
116+
#Preview("SwiftUI") {
117+
SignInWithOAuth()
118+
}
119+
120+
#Preview("UIKit") {
121+
SignInWithOAuthViewController()
122+
}

Examples/Examples/ExamplesApp.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ struct ExamplesApp: App {
2222
let supabase = SupabaseClient(
2323
supabaseURL: Secrets.supabaseURL,
2424
supabaseKey: Secrets.supabaseAnonKey,
25-
options: .init(global: .init(logger: ConsoleLogger()))
25+
options: .init(
26+
auth: .init(redirectToURL: Constants.redirectToURL),
27+
global: .init(
28+
logger: ConsoleLogger()
29+
)
30+
)
2631
)
2732

2833
struct ConsoleLogger: SupabaseLogger {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// UIViewControllerWrapper.swift
3+
// Examples
4+
//
5+
// Created by Guilherme Souza on 10/04/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct UIViewControllerWrapper<T: UIViewController>: UIViewControllerRepresentable {
11+
typealias UIViewControllerType = T
12+
13+
let viewController: T
14+
15+
init(_ viewController: T) {
16+
self.viewController = viewController
17+
}
18+
19+
func makeUIViewController(context _: Context) -> T {
20+
viewController
21+
}
22+
23+
func updateUIViewController(_: T, context _: Context) {
24+
// Update the view controller if needed
25+
}
26+
}

0 commit comments

Comments
 (0)