> ## Documentation Index
> Fetch the complete documentation index at: https://docs.turnkey.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Social logins (OAuth)

> Implement Google, Apple, Discord, and X OAuth using the Turnkey Swift SDK.

export const FeatureCard = ({title, description, icon, logo, href}) => {
  return <a href={href} className="not-prose font-normal group ring-0 ring-transparent cursor-pointer block rounded-lg border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-transparent p-5 no-underline hover:border-primary/40 transition-colors">
      <div className="tk-card-row">
        <span className="tk-card-icon-wrap">
          {logo ? <img src={`/images/networks/${logo}.svg`} className="tk-card-network-logo" alt="" /> : <span className="tk-card-icon" style={{
    maskImage: `url(/images/icons/${icon}.svg)`,
    WebkitMaskImage: `url(/images/icons/${icon}.svg)`
  }} />}
        </span>
        <div>
          <div className="font-semibold text-sm text-zinc-950 dark:text-white group-hover:text-primary transition-colors">
            {title}
          </div>
          {description && <div className="text-sm text-zinc-500 dark:text-zinc-400 mt-1">
              {description}
            </div>}
        </div>
      </div>
    </a>;
};

## Overview

This guide shows how to implement social logins with the Turnkey Swift SDK.\
The SDK launches the provider in the system browser, retrieves an OIDC token, and (by default) completes login or signup through the Auth Proxy. The examples below use SwiftUI, but the SDK works with any Swift framework.

Turnkey supports any OIDC provider. The SDK provides convenience helpers for popular providers (Google, Apple, Discord, X).
For other providers, run your own OAuth flow to obtain an OIDC token and complete authentication with `completeOAuth(oidcToken:publicKey:...)`.

Before you begin:

* Ensure you've completed the setup in [Getting Started](/solutions/embedded-wallets/integration-guide/swift/getting-started).
* Set provider client IDs and `appScheme` in your `TurnkeyConfig`; configure `redirectUri` in the Turnkey Dashboard (Auth Proxy).
* Add your app scheme to iOS URL Types (Info.plist) so the OAuth redirect returns to your app.

## Configure providers

Define your app scheme and provider client IDs directly in `TurnkeyConfig`.

Each provider takes a `primaryClientId` and an optional `secondaryClientIds` array. Any `secondaryClientIds` you pass are registered as additional OIDC audiences on the sub-organization at creation time, which lets a single Turnkey user be authenticated by multiple client IDs (typically used by apps that have both web and mobile versions sharing one identity).

<Note>
  Apple Sign-In on iOS uses the **native** Apple Sign-In flow. The `serviceId` on `AppleOAuthPrimaryClientId` is only needed if you want to use the legacy web-based Apple Sign-In flow (`handleAppleWebOAuth`).
</Note>

```swift DemoWalletApp.swift theme={"system"}
import SwiftUI
import TurnkeySwift

@main
struct DemoWalletApp: App {
    @StateObject private var turnkey: TurnkeyContext

    init() {
        let config = TurnkeyConfig(
            apiUrl: "https://api.turnkey.com",
            authProxyUrl: "https://authproxy.turnkey.com",
            authProxyConfigId: "<your_auth_proxy_config_id>",
            rpId: "<your_rp_id>",
            organizationId: "<your_organization_id>",
            auth: .init(
                oauth: .init(
                    appScheme: "<your-app-scheme>",
                    providers: .init(
                        google: .init(
                            primaryClientId: .init(webClientId: "<your_google_web_client_id>")
                            // secondaryClientIds: ["<another_google_client_id>"]
                        ),
                        apple: .init(
                            // primaryClientId: .init(serviceId: "<your_apple_services_id>") - this is only needed if you're using handleAppleWebOauth.
                            // secondaryClientIds: ["<another_apple_client_id>"]
                        ),
                        x: .init(primaryClientId: "<your_x_client_id>"),
                        discord: .init(primaryClientId: "<your_discord_client_id>")
                    )
                )
            )
        )
        TurnkeyContext.configure(config)
        _turnkey = StateObject(wrappedValue: TurnkeyContext.shared)
    }

    var body: some Scene {
        WindowGroup { /* ... */ }
    }
}
```

<Note>
  By default, Turnkey hosts the OAuth redirect and origin pages at
  `https://oauth-redirect.turnkey.com` and `https://oauth-origin.turnkey.com`,
  which forward back into your app via the `appScheme` you configured. If
  you'd rather host these yourself, you can set a `redirectUri` in your
  `TurnkeyConfig`. Whatever URL you set must match the one registered in the
  provider's developer dashboard.
</Note>

## Helper: presentation anchor

All OAuth helpers require an `ASPresentationAnchor` to present the system web auth session:

```swift Anchor.swift theme={"system"}
import SwiftUI
import AuthenticationServices

func defaultAnchor() -> ASPresentationAnchor? {
    UIApplication.shared
        .connectedScenes
        .compactMap { $0 as? UIWindowScene }
        .first(where: { $0.activationState == .foregroundActive })?
        .windows
        .first(where: { $0.isKeyWindow })
}
```

## OIDC: Google and Apple

Use `handleGoogleOAuth` or `handleAppleOAuth`.

### Google

In the **Google developer console**, set the authorized redirect URL to `https://oauth-redirect.turnkey.com/?scheme=YOURAPPSCHEME/` and the authorized JavaScript origin to `https://oauth-origin.turnkey.com/`. Replace `YOURAPPSCHEME` with the `appScheme` you set in `OAuthConfig`.

### Apple

`handleAppleOAuth` uses the **native** Sign in with Apple flow on iOS. For this to work you must:

* Enable the **Sign in with Apple** capability for your app in **Xcode** (Signing & Capabilities).
* Enable **Sign in with Apple** for the app identifier in the **Apple Developer** dashboard.

The native flow authenticates against the Apple **Services ID** configured in `AppleOAuthPrimaryClientId.serviceId`; no redirect URL setup is required for it.

<Note>
  `handleAppleWebOauth` is also exposed but **deprecated**. It's kept for
  backwards compatibility with older SDK versions and forces the web-based
  Apple OAuth flow on iOS using `serviceId` as the audience. Only use it if
  you specifically need to force the web flow. The web flow uses
  Turnkey's redirect and origin by default. Set the Services ID's return URL to
  `https://oauth-redirect.turnkey.com/?scheme=YOURAPPSCHEME/` and its
  domain/origin to `https://oauth-origin.turnkey.com/` in the Apple Developer
  dashboard.
</Note>

```swift LoginView.swift theme={"system"}
import SwiftUI
import AuthenticationServices
import TurnkeySwift

struct LoginView: View {
    @EnvironmentObject var turnkey: TurnkeyContext

    var body: some View {
        VStack(spacing: 12) {
            Button("Continue with Google") {
                Task {
                    guard let anchor = defaultAnchor() else { return }
                    try await turnkey.handleGoogleOAuth(anchor: anchor)
                }
            }
            Button("Continue with Apple") {
                Task {
                    guard let anchor = defaultAnchor() else { return }
                    try await turnkey.handleAppleOAuth(anchor: anchor)
                }
            }
        }
        .padding()
    }
}
```

Optional parameters:

* `clientId`: Override the configured client ID.
* `sessionKey`: Store the resulting session under a custom key.
* `additionalState`: Append extra key-value pairs to the OAuth request state.

## OAuth2 PKCE: Discord and X

Use `handleDiscordOAuth` or `handleXOauth`. In the **Discord** and **X (Twitter) developer portals**, set the redirect URI to `YOUR_APP_SCHEME://` (matching the `appScheme` you set in `OAuthConfig`).

```swift LoginView.swift theme={"system"}
import SwiftUI
import AuthenticationServices
import TurnkeySwift

struct LoginView: View {
    @EnvironmentObject var turnkey: TurnkeyContext

    var body: some View {
        VStack(spacing: 12) {
            Button("Continue with Discord") {
                Task {
                    guard let anchor = defaultAnchor() else { return }
                    try await turnkey.handleDiscordOAuth(anchor: anchor)
                }
            }
            Button("Continue with X") {
                Task {
                    guard let anchor = defaultAnchor() else { return }
                    try await turnkey.handleXOauth(anchor: anchor)
                }
            }
        }
        .padding()
    }
}
```

## Advanced: onOAuthSuccess callback

If you pass `onOAuthSuccess`, the helper returns early with the `oidcToken` and the `publicKey` associated with the session.
You can then call `completeOAuth(...)` yourself (for example, to customize `sessionKey` or sub-organization creation).

```swift LoginView.swift theme={"system"}
import SwiftUI
import AuthenticationServices
import TurnkeySwift

struct LoginView: View {
    @EnvironmentObject var turnkey: TurnkeyContext

    var body: some View {
        Button("Continue with Google") {
            Task {
                guard let anchor = defaultAnchor() else { return }
                try await turnkey.handleGoogleOAuth(
                    anchor: anchor,
                    sessionKey: "main",
                    onOAuthSuccess: { success in
                        // success.oidcToken, success.publicKey, success.providerName
                        Task {
                            _ = try await turnkey.completeOAuth(
                                oidcToken: success.oidcToken,
                                publicKey: success.publicKey,
                                sessionKey: "main"
                            )
                        }
                    }
                )
            }
        }
    }
}
```

<Note>Wrap async work in a `Task` since the callback is not `async`.</Note>

## Using completeOAuth directly

If you already obtained an OIDC token from your own OAuth flow, call `completeOAuth(oidcToken:publicKey:...)` to finish authentication via the Auth Proxy.

<Note>
  The `publicKey` must match the key used to compute the nonce included in the
  OIDC token.
</Note>

```swift theme={"system"}
let result = try await turnkey.completeOAuth(
    oidcToken: "<oidc_token_from_provider>",
    publicKey: "<matching_public_key>",
    sessionKey: "main"
)
// result.session is stored automatically when completeOAuth succeeds
```

For more information, refer to the [Social Logins](/features/authentication/social-logins) guide.

***

## Next steps

<FeatureCard title="Signing" icon="file-code-01" href="/solutions/embedded-wallets/integration-guide/swift/signing" description="Learn how to sign transactions and messages using wallets and accounts." />
