Skip to content

feat(auth): implement linkIdentity with OIDC #776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
30 changes: 25 additions & 5 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@
/// - Parameters:
/// - configuration: The client configuration.
public init(configuration: Configuration) {
AuthClient.globalClientID += 1

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 96 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6
clientID = AuthClient.globalClientID

Check warning on line 97 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 97 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 97 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Check warning on line 97 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

reference to static property 'globalClientID' is not concurrency-safe because it involves shared mutable state; this is an error in Swift 6

Dependencies[clientID] = Dependencies(
configuration: configuration,
Expand All @@ -104,7 +104,7 @@
sessionStorage: .live(clientID: clientID),
sessionManager: .live(clientID: clientID),
logger: configuration.logger.map {
AuthClientLoggerDecorator(clientID: clientID, decoratee: $0)

Check warning on line 107 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6

Check warning on line 107 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6

Check warning on line 107 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6

Check warning on line 107 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

nonisolated property 'clientID' can not be referenced from a non-isolated context; this is an error in Swift 6
}
)

Expand Down Expand Up @@ -380,7 +380,15 @@
/// The ID token is verified for validity and a new session is established.
@discardableResult
public func signInWithIdToken(credentials: OpenIDConnectCredentials) async throws -> Session {
try await _signIn(
try await _signInWithIdToken(credentials: credentials, linkIdentity: false)
}

private func _signInWithIdToken(credentials: OpenIDConnectCredentials, linkIdentity: Bool)
async throws -> Session
{
var credentials = credentials
credentials.linkIdentity = linkIdentity
return try await _signIn(
request: .init(
url: configuration.url.appendingPathComponent("token"),
method: .post,
Expand Down Expand Up @@ -578,7 +586,8 @@

if codeVerifier == nil {
logger?.error(
"code verifier not found, a code verifier should exist when calling this method.")
"code verifier not found, a code verifier should exist when calling this method."
)
}

let session: Session = try await api.execute(
Expand Down Expand Up @@ -804,7 +813,8 @@
case .implicit:
guard isImplicitGrantFlow(params: params) else {
throw AuthError.implicitGrantRedirect(
message: "Not a valid implicit grant flow URL: \(url)")
message: "Not a valid implicit grant flow URL: \(url)"
)
}
return try await handleImplicitGrantFlow(params: params)

Expand All @@ -821,7 +831,8 @@

if let errorDescription = params["error_description"] {
throw AuthError.implicitGrantRedirect(
message: errorDescription.replacingOccurrences(of: "+", with: " "))
message: errorDescription.replacingOccurrences(of: "+", with: " ")
)
}

guard
Expand Down Expand Up @@ -1177,6 +1188,14 @@
try await user().identities ?? []
}

/// Link an identity to the current user using an ID token.
@discardableResult
public func linkIdentityWithIdToken(
credentials: OpenIDConnectCredentials
) async throws -> Session {
try await _signInWithIdToken(credentials: credentials, linkIdentity: true)
}

/// Links an OAuth identity to an existing user.
///
/// This method supports the PKCE flow.
Expand Down Expand Up @@ -1378,7 +1397,8 @@
) throws -> URL {
guard
var components = URLComponents(
url: url, resolvingAgainstBaseURL: false
url: url,
resolvingAgainstBaseURL: false
)
else {
throw URLError(.badURL)
Expand Down Expand Up @@ -1442,7 +1462,7 @@
final class DefaultPresentationContextProvider: NSObject,
ASWebAuthenticationPresentationContextProviding
{
func presentationAnchor(for _: ASWebAuthenticationSession) -> ASPresentationAnchor {

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement

Check warning on line 1465 in Sources/Auth/AuthClient.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MACOS, 15.4)

main actor-isolated instance method 'presentationAnchor(for:)' cannot be used to satisfy nonisolated protocol requirement
ASPresentationAnchor()
}
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/Auth/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@
/// Verification token received when the user completes the captcha on the site.
public var gotrueMetaSecurity: AuthMetaSecurity?

var linkIdentity: Bool = false

public init(
provider: Provider,
idToken: String,
Expand Down Expand Up @@ -500,7 +502,7 @@
self.phone = phone
self.password = password
self.nonce = nonce
self.emailChangeToken = emailChangeToken

Check warning on line 505 in Sources/Auth/Types.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, MAC_CATALYST, 15.4)

'emailChangeToken' is deprecated: This is an old field, stop relying on it.

Check warning on line 505 in Sources/Auth/Types.swift

View workflow job for this annotation

GitHub Actions / xcodebuild (15.4) (test, IOS, 15.4)

'emailChangeToken' is deprecated: This is an old field, stop relying on it.
self.data = data
}
}
Expand Down
41 changes: 39 additions & 2 deletions Tests/AuthTests/AuthClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,43 @@ final class AuthClientTests: XCTestCase {
expectNoDifference(receivedURL.value?.absoluteString, url)
}

func testLinkIdentityWithIdToken() async throws {
Mock(
url: clientURL.appendingPathComponent("token"),
ignoreQuery: true,
statusCode: 200,
data: [.post: MockData.session]
)
.snapshotRequest {
#"""
curl \
--request POST \
--header "Content-Length: 166" \
--header "Content-Type: application/json" \
--header "X-Client-Info: auth-swift/0.0.0" \
--header "X-Supabase-Api-Version: 2024-01-01" \
--header "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0" \
--data "{\"access_token\":\"access-token\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"id_token\":\"id-token\",\"link_identity\":true,\"nonce\":\"nonce\",\"provider\":\"apple\"}" \
"http://localhost:54321/auth/v1/token?grant_type=id_token"
"""#
}
.register()

let sut = makeSUT()

try await sut.linkIdentityWithIdToken(
credentials: OpenIDConnectCredentials(
provider: .apple,
idToken: "id-token",
accessToken: "access-token",
nonce: "nonce",
gotrueMetaSecurity: AuthMetaSecurity(
captchaToken: "captcha-token"
)
)
)
}

func testAdminListUsers() async throws {
Mock(
url: clientURL.appendingPathComponent("admin/users"),
Expand Down Expand Up @@ -712,12 +749,12 @@ final class AuthClientTests: XCTestCase {
#"""
curl \
--request POST \
--header "Content-Length: 145" \
--header "Content-Length: 167" \
--header "Content-Type: application/json" \
--header "X-Client-Info: auth-swift/0.0.0" \
--header "X-Supabase-Api-Version: 2024-01-01" \
--header "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0" \
--data "{\"access_token\":\"access-token\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"id_token\":\"id-token\",\"nonce\":\"nonce\",\"provider\":\"apple\"}" \
--data "{\"access_token\":\"access-token\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"id_token\":\"id-token\",\"link_identity\":false,\"nonce\":\"nonce\",\"provider\":\"apple\"}" \
"http://localhost:54321/auth/v1/token?grant_type=id_token"
"""#
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ curl \
--header "Content-Type: application/json" \
--header "X-Client-Info: gotrue-swift/x.y.z" \
--header "X-Supabase-Api-Version: 2024-01-01" \
--data "{\"access_token\":\"access-token\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"id_token\":\"id-token\",\"nonce\":\"nonce\",\"provider\":\"apple\"}" \
--data "{\"access_token\":\"access-token\",\"gotrue_meta_security\":{\"captcha_token\":\"captcha-token\"},\"id_token\":\"id-token\",\"link_identity\":false,\"nonce\":\"nonce\",\"provider\":\"apple\"}" \
"http://localhost:54321/auth/v1/token?grant_type=id_token"
Loading