Skip to content

Commit 90f605c

Browse files
authored
Merge pull request #584 from stytchauth/apple-oauth-attach
Add oauth attach and apple oauth attach
2 parents e4577da + c324b3a commit 90f605c

File tree

7 files changed

+101
-80
lines changed

7 files changed

+101
-80
lines changed

README.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,6 @@ In addition to installing the Swift package, it is highly recommended to clone t
197197

198198

199199

200-
## 💬 Talk to a Stytch iOS Engineer
201-
202-
[Nidal](https://www.linkedin.com/in/nidal-fakhouri/) 👨‍💻 is our Stytch iOS lead 🍎 and is available to answer any questions about the Stytch iOS SDK 📱. He can also help you get started quickly 🚀.
203-
204-
You can book time with him [here](https://calendly.com/nfakhouri-stytch/30min) 📅.
205-
206-
207-
208-
209200
## 🤝 Get Help And Join The Community
210201

211202
Join the discussion, ask questions, and suggest new features in our ​[Slack community](https://stytch.com/docs/resources/support/overview)!

Sources/StytchCore/Generated/StytchClient.OAuth.Apple.authenticateWithApple+AsyncVariants.generated.swift

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
2+
// DO NOT EDIT
3+
import Combine
4+
import Foundation
5+
6+
public extension StytchClient.OAuth {
7+
/// Generate an OAuth Attach Token to pre-associate an OAuth flow with an existing Stytch User.
8+
/// You must have an active Stytch session to use this endpoint.
9+
/// Pass the returned oauth_attach_token to the same provider's OAuth Start endpoint to treat this OAuth flow as a login for that user instead of a signup for a new user.
10+
func attach(parameters: AttachParameters, completion: @escaping Completion<OAuthAttachResponse>) {
11+
Task {
12+
do {
13+
completion(.success(try await attach(parameters: parameters)))
14+
} catch {
15+
completion(.failure(error))
16+
}
17+
}
18+
}
19+
20+
/// Generate an OAuth Attach Token to pre-associate an OAuth flow with an existing Stytch User.
21+
/// You must have an active Stytch session to use this endpoint.
22+
/// Pass the returned oauth_attach_token to the same provider's OAuth Start endpoint to treat this OAuth flow as a login for that user instead of a signup for a new user.
23+
func attach(parameters: AttachParameters) -> AnyPublisher<OAuthAttachResponse, Error> {
24+
return Deferred {
25+
Future({ promise in
26+
Task {
27+
do {
28+
promise(.success(try await attach(parameters: parameters)))
29+
} catch {
30+
promise(.failure(error))
31+
}
32+
}
33+
})
34+
}
35+
.eraseToAnyPublisher()
36+
}
37+
}

Sources/StytchCore/StytchClient/OAuth/OAuth+Apple.swift

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public extension StytchClient.OAuth {
3333
parameters: AuthenticateParameters(
3434
idToken: authenticateResult.idToken,
3535
nonce: rawNonce,
36+
oauthAttachToken: parameters.oauthAttachToken,
3637
sessionDurationMinutes: parameters.sessionDurationMinutes
3738
)
3839
)
@@ -59,21 +60,6 @@ public extension StytchClient.OAuth {
5960

6061
return authenticateResponse
6162
}
62-
63-
// sourcery: AsyncVariants, (NOTE: - must use /// doc comment styling)
64-
/// This function is intended for rare cases where you must authenticate with Apple only and collect the JWT.
65-
/// This function will not create a Stytch user.
66-
public func authenticateWithApple() async throws -> String {
67-
let rawNonce = try cryptoClient.dataWithRandomBytesOfCount(32).toHexString()
68-
69-
let authenticateResult = try await appleOAuthClient.authenticate(
70-
configureController: { _ in },
71-
nonce: cryptoClient.sha256(Data(rawNonce.utf8)).base64EncodedString()
72-
)
73-
74-
// the idToken is the JWT
75-
return authenticateResult.idToken
76-
}
7763
}
7864
}
7965

@@ -100,6 +86,7 @@ public extension StytchClient.OAuth.Apple {
10086
/// The dedicated parameters type for ``StytchClient/OAuth-swift.struct/Apple-swift.struct/start(parameters:)-5rxqg`` calls.
10187
struct StartParameters {
10288
let sessionDurationMinutes: Minutes
89+
let oauthAttachToken: String?
10390

10491
#if !os(watchOS)
10592
let presentationContextProvider: ASAuthorizationControllerPresentationContextProviding?
@@ -108,21 +95,29 @@ public extension StytchClient.OAuth.Apple {
10895
#if !os(watchOS)
10996
/// - Parameters:
11097
/// - sessionDurationMinutes: The duration, in minutes, of the requested session. Defaults to 5 minutes.
98+
/// - oauthAttachToken: A single-use token for connecting the Stytch User selection from an OAuth Attach request to the corresponding OAuth Start request.
11199
/// - presentationContextProvider: This native Apple authorization type allows you to present Sign In With Apple in the window of your choosing.
112100
public init(
113101
sessionDurationMinutes: Minutes = StytchClient.defaultSessionDuration,
102+
oauthAttachToken: String? = nil,
114103
presentationContextProvider: ASAuthorizationControllerPresentationContextProviding? = nil
115104
) {
116105
self.sessionDurationMinutes = sessionDurationMinutes
106+
self.oauthAttachToken = oauthAttachToken
117107
self.presentationContextProvider = presentationContextProvider
118108
}
119109

120110
#else
121111

122112
/// - Parameters:
123113
/// - sessionDurationMinutes: The duration, in minutes, of the requested session. Defaults to 5 minutes.
124-
public init(sessionDurationMinutes: Minutes = StytchClient.defaultSessionDuration) {
114+
/// - oauthAttachToken: A single-use token for connecting the Stytch User selection from an OAuth Attach request to the corresponding OAuth Start request.
115+
public init(
116+
sessionDurationMinutes: Minutes = StytchClient.defaultSessionDuration,
117+
oauthAttachToken: String? = nil,
118+
) {
125119
self.sessionDurationMinutes = sessionDurationMinutes
120+
self.oauthAttachToken = oauthAttachToken
126121
}
127122
#endif
128123
}
@@ -132,6 +127,7 @@ extension StytchClient.OAuth.Apple {
132127
struct AuthenticateParameters: Codable, Sendable {
133128
let idToken: String
134129
let nonce: String
130+
let oauthAttachToken: String?
135131
let sessionDurationMinutes: Minutes
136132
}
137133

Sources/StytchCore/StytchClient/OAuth/OAuthRoute.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
enum OAuthRoute: RouteType {
22
case authenticate
3+
case attach
34
case apple(AppleRoute)
45

56
var path: Path {
67
switch self {
78
case .authenticate:
89
return "authenticate"
10+
case .attach:
11+
return "attach"
912
case let .apple(route):
1013
return "apple".appendingPath(route.path)
1114
}

Sources/StytchCore/StytchClient/OAuth/StytchClient+OAuth.swift

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ public extension StytchClient {
3838
throw error
3939
}
4040
}
41+
42+
// sourcery: AsyncVariants, (NOTE: - must use /// doc comment styling)
43+
/// Generate an OAuth Attach Token to pre-associate an OAuth flow with an existing Stytch User.
44+
/// You must have an active Stytch session to use this endpoint.
45+
/// Pass the returned oauth_attach_token to the same provider's OAuth Start endpoint to treat this OAuth flow as a login for that user instead of a signup for a new user.
46+
public func attach(parameters: AttachParameters) async throws -> OAuthAttachResponse {
47+
try await router.post(to: .attach, parameters: parameters)
48+
}
4149
}
4250
}
4351

@@ -112,25 +120,6 @@ public extension StytchClient.OAuth {
112120
}
113121
#endif
114122

115-
public extension StytchClient.OAuth {
116-
/// The dedicated parameters type for ``authenticate(parameters:)-3tjwd`` calls.
117-
struct AuthenticateParameters: Encodable, Sendable {
118-
let token: String
119-
let sessionDurationMinutes: Minutes
120-
121-
/// - Parameters:
122-
/// - token: The token returned from the identity provider as parsed from the final/complete redirect URL.
123-
/// - sessionDurationMinutes: The duration, in minutes, of the requested session. Defaults to 5 minutes.
124-
public init(
125-
token: String,
126-
sessionDurationMinutes: Minutes = StytchClient.defaultSessionDuration
127-
) {
128-
self.token = token
129-
self.sessionDurationMinutes = sessionDurationMinutes
130-
}
131-
}
132-
}
133-
134123
public extension StytchClient.OAuth {
135124
/// The concrete response type for OAuth `authenticate` calls.
136125
typealias OAuthAuthenticateResponse = Response<OAuthAuthenticateResponseData>
@@ -157,4 +146,37 @@ public extension StytchClient.OAuth {
157146
/// Note that these values will vary based on the OAuth provider in question, e.g. id_token is only returned by OIDC compliant identity providers.
158147
public let providerValues: OAuthProviderValues
159148
}
149+
150+
/// The dedicated parameters type for ``authenticate(parameters:)-3tjwd`` calls.
151+
struct AuthenticateParameters: Encodable, Sendable {
152+
let token: String
153+
let sessionDurationMinutes: Minutes
154+
155+
/// - Parameters:
156+
/// - token: The token returned from the identity provider as parsed from the final/complete redirect URL.
157+
/// - sessionDurationMinutes: The duration, in minutes, of the requested session. Defaults to 5 minutes.
158+
public init(
159+
token: String,
160+
sessionDurationMinutes: Minutes = StytchClient.defaultSessionDuration
161+
) {
162+
self.token = token
163+
self.sessionDurationMinutes = sessionDurationMinutes
164+
}
165+
}
166+
}
167+
168+
public extension StytchClient.OAuth {
169+
typealias OAuthAttachResponse = Response<OAuthAttachResponseData>
170+
171+
struct OAuthAttachResponseData: Codable, Sendable {
172+
public let oauthAttachToken: String
173+
}
174+
175+
struct AttachParameters: Encodable, Sendable {
176+
public let provider: String
177+
178+
public init(provider: String) {
179+
self.provider = provider
180+
}
181+
}
160182
}

Stytch/DemoApps/StytchSessions/StytchConsumerSessionsViewController.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,16 @@ final class StytchConsumerSessionsViewController: UIViewController {
7171
func sendAndAuthenticateSmsOtp() {
7272
Task {
7373
do {
74-
guard let phoneNumber = try await presentTextFieldAlertWithTitle(alertTitle: "Enter Your Phone Number In The Format xxxxxxxxxx", keyboardType: .numberPad) else {
74+
// so you can hard code a number if needed
75+
var phoneNumber: String?
76+
if phoneNumber?.isEmpty == true {
77+
phoneNumber = try await presentTextFieldAlertWithTitle(alertTitle: "Enter Your Phone Number In The Format xxxxxxxxxx", keyboardType: .numberPad)
78+
}
79+
80+
guard let phoneNumber else {
7581
throw TextFieldAlertError.emptyString
7682
}
83+
7784
let loginOrCreateResponse = try await StytchClient.otps.loginOrCreate(parameters: .init(deliveryMethod: .sms(phoneNumber: "+1\(phoneNumber)", enableAutofill: false)))
7885

7986
guard let code = try await presentTextFieldAlertWithTitle(alertTitle: "Enter The OTP Code", keyboardType: .numberPad) else {

0 commit comments

Comments
 (0)