Skip to content

Commit

Permalink
feat(auth): Add signInAnonymously (#297)
Browse files Browse the repository at this point in the history
* feat(auth): add `signInAnonymously` method

* Add tests
  • Loading branch information
grdsdev authored Apr 1, 2024
1 parent bfbcddd commit 4c25a3e
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
79BD76772B59C3E300CA3D68 /* UserStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BD76762B59C3E300CA3D68 /* UserStore.swift */; };
79BD76792B59C53900CA3D68 /* ChannelStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BD76782B59C53900CA3D68 /* ChannelStore.swift */; };
79BD767B2B59C61300CA3D68 /* MessageStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BD767A2B59C61300CA3D68 /* MessageStore.swift */; };
79C9B8E52BBB16C0003AD942 /* SignInAnonymously.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C9B8E42BBB16C0003AD942 /* SignInAnonymously.swift */; };
79D884CA2B3C18830009EA4A /* SlackCloneApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D884C92B3C18830009EA4A /* SlackCloneApp.swift */; };
79D884CC2B3C18830009EA4A /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D884CB2B3C18830009EA4A /* AppView.swift */; };
79D884CE2B3C18840009EA4A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79D884CD2B3C18840009EA4A /* Assets.xcassets */; };
Expand Down Expand Up @@ -112,6 +113,7 @@
79BD76762B59C3E300CA3D68 /* UserStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStore.swift; sourceTree = "<group>"; };
79BD76782B59C53900CA3D68 /* ChannelStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelStore.swift; sourceTree = "<group>"; };
79BD767A2B59C61300CA3D68 /* MessageStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStore.swift; sourceTree = "<group>"; };
79C9B8E42BBB16C0003AD942 /* SignInAnonymously.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInAnonymously.swift; sourceTree = "<group>"; };
79D884C72B3C18830009EA4A /* SlackClone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SlackClone.app; sourceTree = BUILT_PRODUCTS_DIR; };
79D884C92B3C18830009EA4A /* SlackCloneApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlackCloneApp.swift; sourceTree = "<group>"; };
79D884CB2B3C18830009EA4A /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -258,6 +260,7 @@
793E030C2B2DAB5700AC7DED /* SignInWithApple.swift */,
7940E3142B36187A0089BEE1 /* GoogleSignInWithWebFlow.swift */,
79E2B5542B9788BF0042CD21 /* GoogleSignInSDKFlow.swift */,
79C9B8E42BBB16C0003AD942 /* SignInAnonymously.swift */,
);
path = Auth;
sourceTree = "<group>";
Expand Down Expand Up @@ -505,6 +508,7 @@
793895CA2954ABFF0044F2B8 /* ExamplesApp.swift in Sources */,
797EFB682BABD90500098D6B /* Stringfy.swift in Sources */,
797EFB6C2BABE1B800098D6B /* FileObjectDetailView.swift in Sources */,
79C9B8E52BBB16C0003AD942 /* SignInAnonymously.swift in Sources */,
797EFB6A2BABDF3800098D6B /* BucketDetailView.swift in Sources */,
793E030D2B2DAB5700AC7DED /* SignInWithApple.swift in Sources */,
793E030B2B2CEDDA00AC7DED /* ActionState.swift in Sources */,
Expand Down
3 changes: 3 additions & 0 deletions Examples/Examples/Auth/AuthView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct AuthView: View {
case signInWithApple
case googleSignInWebFlow
case googleSignInSDKFlow
case signInAnonymously

var title: String {
switch self {
Expand All @@ -22,6 +23,7 @@ struct AuthView: View {
case .signInWithApple: "Sign in with Apple"
case .googleSignInWebFlow: "Google Sign in (Web Flow)"
case .googleSignInSDKFlow: "Google Sign in (GIDSignIn SDK Flow)"
case .signInAnonymously: "Sign in Anonymously"
}
}
}
Expand Down Expand Up @@ -50,6 +52,7 @@ extension AuthView.Option: View {
case .signInWithApple: SignInWithApple()
case .googleSignInWebFlow: GoogleSignInWithWebFlow()
case .googleSignInSDKFlow: GoogleSignInSDKFlow()
case .signInAnonymously: SignInAnonymously()
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions Examples/Examples/Auth/SignInAnonymously.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// SignInAnonymously.swift
// Examples
//
// Created by Guilherme Souza on 01/04/24.
//

import Supabase
import SwiftUI

struct SignInAnonymously: View {
var body: some View {
Button("Sign in") {
Task {
do {
try await supabase.auth.signInAnonymously()
} catch {
debug("Error signin in anonymously: \(error)")
}
}
}
}
}

#Preview {
SignInAnonymously()
}
2 changes: 1 addition & 1 deletion Examples/supabase/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ redirect_uri = ""
url = ""

[auth.external.github]
enabled = true
enabled = false
client_id = "12d1131cd3582f942c71"
secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"
31 changes: 27 additions & 4 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,31 @@ public actor AuthClient {
)
}

/// Creates a new anonymous user.
/// - Parameters:
/// - data: A custom data object to store the user's metadata. This maps to the
/// `auth.users.raw_user_meta_data` column. The `data` should be a JSON object that includes
/// user-specific info, such as their first and last name.
/// - captchaToken: Verification token received when the user completes the captcha.
@discardableResult
public func signInAnonymously(
data: [String: AnyJSON]? = nil,
captchaToken: String? = nil
) async throws -> Session {
try await _signIn(
request: Request(
path: "/signup",
method: .post,
body: configuration.encoder.encode(
SignUpRequest(
data: data,
gotrueMetaSecurity: captchaToken.map { AuthMetaSecurity(captchaToken: $0) }
)
)
)
)
}

private func _signIn(request: Request) async throws -> Session {
await sessionManager.remove()

Expand All @@ -370,10 +395,8 @@ public actor AuthClient {
decoder: configuration.decoder
)

if session.user.emailConfirmedAt != nil || session.user.confirmedAt != nil {
try await sessionManager.update(session)
eventEmitter.emit(.signedIn, session: session)
}
try await sessionManager.update(session)
eventEmitter.emit(.signedIn, session: session)

return session
}
Expand Down
55 changes: 55 additions & 0 deletions Tests/AuthTests/AuthClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,61 @@ final class AuthClientTests: XCTestCase {
XCTAssertEqual(removeCallCount.value, 1)
}

func testSignInAnonymously() async throws {
let emitReceivedEvents = LockIsolated<[(AuthChangeEvent, Session?)]>([])

eventEmitter.emit = { @Sendable event, session, _ in
emitReceivedEvents.withValue {
$0.append((event, session))
}
}
sessionManager.remove = { @Sendable in }
sessionManager.update = { @Sendable _ in }

api.execute = { @Sendable _ in
.stub(
"""
{
"access_token" : "eyJhbGciOiJIUzI1NiIsImtpZCI6ImpIaU1GZmtNTzRGdVROdXUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzExOTk0NzEzLCJpYXQiOjE3MTE5OTExMTMsImlzcyI6Imh0dHBzOi8vYWp5YWdzaHV6bnV2anFoampmdG8uc3VwYWJhc2UuY28vYXV0aC92MSIsInN1YiI6ImJiZmE5MjU0LWM1ZDEtNGNmZi1iYTc2LTU2YmYwM2IwNWEwMSIsImVtYWlsIjoiIiwicGhvbmUiOiIiLCJhcHBfbWV0YWRhdGEiOnt9LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJhbm9ueW1vdXMiLCJ0aW1lc3RhbXAiOjE3MTE5OTExMTN9XSwic2Vzc2lvbl9pZCI6ImMyODlmYTcwLWIzYWUtNDI1Yi05MDQxLWUyZjVhNzBlZTcyYSIsImlzX2Fub255bW91cyI6dHJ1ZX0.whBzmyMv3-AQSaiY6Fi-v_G68Q8oULhB7axImj9qOdw",
"expires_at" : 1711994713,
"expires_in" : 3600,
"refresh_token" : "0xS9iJUWdXnWlCJtFiXk5A",
"token_type" : "bearer",
"user" : {
"app_metadata" : {
},
"aud" : "authenticated",
"created_at" : "2024-04-01T17:05:13.013312Z",
"email" : "",
"id" : "bbfa9254-c5d1-4cff-ba76-56bf03b05a01",
"identities" : [
],
"is_anonymous" : true,
"last_sign_in_at" : "2024-04-01T17:05:13.018294975Z",
"phone" : "",
"role" : "authenticated",
"updated_at" : "2024-04-01T17:05:13.022041Z",
"user_metadata" : {
}
}
}
""",
code: 200
)
}

let sut = makeSUT()

try await sut.signInAnonymously()

let events = emitReceivedEvents.value.map(\.0)

XCTAssertEqual(events, [.signedIn])
}

private func makeSUT() -> AuthClient {
let configuration = AuthClient.Configuration(
url: clientURL,
Expand Down
11 changes: 11 additions & 0 deletions Tests/AuthTests/RequestsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,17 @@ final class RequestsTests: XCTestCase {
}
}

func testSignInAnonymously() async {
let sut = makeSUT()

await assert {
try await sut.signInAnonymously(
data: ["custom_key": .string("custom_value")],
captchaToken: "captcha-token"
)
}
}

private func assert(_ block: () async throws -> Void) async {
do {
try await block()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
curl \
--request POST \
--header "Apikey: dummy.api.key" \
--header "Content-Type: application/json" \
--header "X-Client-Info: gotrue-swift/x.y.z" \
--data "{\"data\":{\"custom_key\":\"custom_value\"},\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"}}" \
"http://localhost:54321/auth/v1/signup"

0 comments on commit 4c25a3e

Please sign in to comment.