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
4 changes: 4 additions & 0 deletions Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
7928145D2CAB2CE2000B4ADB /* ResetPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7928145C2CAB2CDE000B4ADB /* ResetPasswordView.swift */; };
793895CA2954ABFF0044F2B8 /* ExamplesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793895C92954ABFF0044F2B8 /* ExamplesApp.swift */; };
793895CC2954ABFF0044F2B8 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 793895CB2954ABFF0044F2B8 /* RootView.swift */; };
793895CE2954AC000044F2B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 793895CD2954AC000044F2B8 /* Assets.xcassets */; };
Expand Down Expand Up @@ -77,6 +78,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
7928145C2CAB2CDE000B4ADB /* ResetPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordView.swift; sourceTree = "<group>"; };
793895C62954ABFF0044F2B8 /* Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Examples.app; sourceTree = BUILT_PRODUCTS_DIR; };
793895C92954ABFF0044F2B8 /* ExamplesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExamplesApp.swift; sourceTree = "<group>"; };
793895CB2954ABFF0044F2B8 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -276,6 +278,7 @@
79B1C80A2BABFF6F00D991AA /* Profile */ = {
isa = PBXGroup;
children = (
7928145C2CAB2CDE000B4ADB /* ResetPasswordView.swift */,
79B1C80B2BABFF8000D991AA /* ProfileView.swift */,
794C61D52BAD1E12000E6B0F /* UserIdentityList.swift */,
79B3261B2BF359A50023661C /* UpdateProfileView.swift */,
Expand Down Expand Up @@ -510,6 +513,7 @@
797EFB662BABD82A00098D6B /* BucketList.swift in Sources */,
79E2B55C2B97A2310042CD21 /* UIApplicationExtensions.swift in Sources */,
794EF1222955F26A008C9526 /* AddTodoListView.swift in Sources */,
7928145D2CAB2CE2000B4ADB /* ResetPasswordView.swift in Sources */,
7956405E2954ADE00088A06F /* Secrets.swift in Sources */,
795640682955AEB30088A06F /* Models.swift in Sources */,
79B1C80C2BABFF8000D991AA /* ProfileView.swift in Sources */,
Expand Down
9 changes: 7 additions & 2 deletions Examples/Examples/Auth/AuthController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import SwiftUI
@MainActor
final class AuthController {
var session: Session?
var isPasswordRecoveryFlow: Bool = false

var currentUserID: UUID {
guard let id = session?.user.id else {
Expand All @@ -27,9 +28,13 @@ final class AuthController {
init() {
observeAuthStateChangesTask = Task {
for await (event, session) in supabase.auth.authStateChanges {
guard [.initialSession, .signedIn, .signedOut].contains(event) else { return }
if [.initialSession, .signedIn, .signedOut].contains(event) {
self.session = session
}

self.session = session
if event == .passwordRecovery {
self.isPasswordRecoveryFlow = true
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions Examples/Examples/Auth/AuthWithEmailAndPassword.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ struct AuthWithEmailAndPassword: View {
@State var mode: Mode = .signIn
@State var actionState = ActionState<Result, Error>.idle

@State var isPresentingResetPassword: Bool = false

var body: some View {
Form {
Section {
Expand Down Expand Up @@ -73,13 +75,24 @@ struct AuthWithEmailAndPassword: View {
actionState = .idle
}
}

if mode == .signIn {
Section {
Button("Forgot password? Reset it.") {
isPresentingResetPassword = true
}
}
}
}
.onOpenURL { url in
Task {
await onOpenURL(url)
}
}
.animation(.default, value: mode)
.sheet(isPresented: $isPresentingResetPassword) {
ResetPasswordView()
}
}

@MainActor
Expand Down
2 changes: 1 addition & 1 deletion Examples/Examples/Contants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

enum Constants {
static let redirectToURL = URL(scheme: "com.supabase.swift-examples")!
static let redirectToURL = URL(string: "com.supabase.swift-examples://")!
}

extension URL {
Expand Down
31 changes: 26 additions & 5 deletions Examples/Examples/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ struct HomeView: View {
@State private var mfaStatus: MFAStatus?

var body: some View {
@Bindable var auth = auth

TabView {
ProfileView()
.tabItem {
Expand All @@ -28,11 +30,8 @@ struct HomeView: View {
Label("Storage", systemImage: "externaldrive")
}
}
.task {
// mfaStatus = await verifyMFAStatus()
}
.sheet(unwrapping: $mfaStatus) { $mfaStatus in
MFAFlow(status: mfaStatus)
.sheet(isPresented: $auth.isPasswordRecoveryFlow) {
UpdatePasswordView()
}
}

Expand All @@ -55,6 +54,28 @@ struct HomeView: View {
return nil
}
}

struct UpdatePasswordView: View {
@Environment(\.dismiss) var dismiss

@State var password: String = ""

var body: some View {
Form {
SecureField("Password", text: $password)
.textContentType(.newPassword)

Button("Update password") {
Task {
do {
try await supabase.auth.update(user: UserAttributes(password: password))
dismiss()
} catch {}
}
}
}
}
}
}

struct HomeView_Previews: PreviewProvider {
Expand Down
52 changes: 52 additions & 0 deletions Examples/Examples/Profile/ResetPasswordView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// ResetPasswordView.swift
// Examples
//
// Created by Guilherme Souza on 30/09/24.
//

import SwiftUI
import SwiftUINavigation

struct ResetPasswordView: View {
@State private var email: String = ""
@State private var showAlert = false
@State private var alertMessage = ""

var body: some View {
VStack(spacing: 20) {
Text("Reset Password")
.font(.largeTitle)
.fontWeight(.bold)

TextField("Enter your email", text: $email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.autocapitalization(.none)
.keyboardType(.emailAddress)

Button(action: resetPassword) {
Text("Send Reset Link")
.foregroundColor(.white)
.padding()
.background(Color.blue)
.cornerRadius(10)
}
}
.padding()
.alert("Password reset", isPresented: $showAlert, actions: {}, message: {
Text(alertMessage)
})
}

func resetPassword() {
Task {
do {
try await supabase.auth.resetPasswordForEmail(email)
alertMessage = "Password reset email sent successfully"
} catch {
alertMessage = "Error sending password reset email: \(error.localizedDescription)"
}
showAlert = true
}
}
}
9 changes: 8 additions & 1 deletion Examples/Examples/Profile/UpdateProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ struct UpdateProfileView: View {

@State var email = ""
@State var phone = ""
@State var password = ""

@State var otp = ""
@State var showTokenField = false

var formUpdated: Bool {
emailChanged || phoneChanged
emailChanged || phoneChanged || !password.isEmpty
}

var emailChanged: Bool {
Expand All @@ -42,6 +43,8 @@ struct UpdateProfileView: View {
.keyboardType(.phonePad)
.autocorrectionDisabled()
.textInputAutocapitalization(.never)
SecureField("New password", text: $password)
.textContentType(.newPassword)
}

Section {
Expand Down Expand Up @@ -81,6 +84,10 @@ struct UpdateProfileView: View {
attributes.phone = phone
}

if password.isEmpty == false {
attributes.password = password
}

do {
try await supabase.auth.update(user: attributes, redirectTo: Constants.redirectToURL)

Expand Down
2 changes: 1 addition & 1 deletion Examples/supabase/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ enabled = true
account_sid = "account sid"
message_service_sid = "account service sid"
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
auth_token = "auth token"

# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
# `discord`, `facebook`, `github`, `gitlab`, `google`, `twitch`, `twitter`, `slack`, `spotify`.
Expand Down
2 changes: 2 additions & 0 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,8 @@ public final class AuthClient: Sendable {
/// Gets the session data from a OAuth2 callback URL.
@discardableResult
public func session(from url: URL) async throws -> Session {
logger?.debug("received \(url)")

let params = extractParams(from: url)

if configuration.flowType == .implicit, !isImplicitGrantFlow(params: params) {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Auth/Internal/EventEmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import Helpers

struct AuthStateChangeEventEmitter {
var emitter = EventEmitter<(AuthChangeEvent, Session?)?>(initialEvent: nil, emitsLastEventWhenAttaching: false)
var logger: (any SupabaseLogger)?

func attach(_ listener: @escaping AuthStateChangeListener) -> ObservationToken {
emitter.attach { event in
guard let event else { return }
listener(event.0, event.1)

logger?.verbose("Auth state changed: \(event)")
}
}

Expand Down
5 changes: 3 additions & 2 deletions Sources/Helpers/HTTP/LoggerInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ package struct LoggerInterceptor: HTTPClientInterceptor {
) async throws -> HTTPResponse {
let id = UUID().uuidString
return try await SupabaseLoggerTaskLocal.$additionalContext.withValue(merging: ["requestID": .string(id)]) {
let urlRequest = request.urlRequest

logger.verbose(
"""
Request: \(request.method.rawValue) \(request.url.absoluteString
.removingPercentEncoding ?? "")
Request: \(urlRequest.httpMethod ?? "") \(urlRequest.url?.absoluteString.removingPercentEncoding ?? "")
Body: \(stringfy(request.body))
"""
)
Expand Down
Loading