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

# Email & Phone Login

> Implement Para's unified email and phone authentication flow in Swift.

export const DemoCallout = ({variant = "card", title = "Interactive Demo", description = "Try the live demo to explore authentication flows and customize your modal before integrating."}) => {
  if (variant === "subtle") {
    return <div className="not-prose my-4 px-4 py-3 rounded-xl border border-orange-200 bg-orange-50/50">
        <div className="flex items-center justify-between gap-4">
          <p className="text-sm text-gray-700 m-0">
            {description}
          </p>
          <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose flex-shrink-0 inline-flex items-center gap-2 px-3 py-1.5 text-xs font-semibold text-orange-600 bg-white border border-orange-200 rounded-lg hover:bg-orange-50 transition-colors no-underline">
            Try Demo
            <svg width="12" height="12" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
              <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="currentColor" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </a>
        </div>
      </div>;
  }
  return <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose block my-4 p-5 rounded-xl bg-gradient-to-r from-orange-600 via-pink-600 to-purple-600 hover:opacity-95 transition-opacity no-underline">
      <div className="flex items-center justify-between gap-4">
        <div>
          <h3 className="text-base font-semibold text-white m-0">{title}</h3>
          <p className="text-xs text-white/80 mt-1 m-0">{description}</p>
        </div>
        <div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center">
          <svg width="14" height="14" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="white" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </div>
      </div>
    </a>;
};

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

## Overview

Para One Click Login is the default experience—Para hosts the entire flow for existing users and new signups. If you turn on passkey or password requirements in the Developer Portal, the optional sections below show how to handle them.

<Note>
  **Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
  [dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
  code will work for verification with these test credentials. These credentials are for beta testing only. You can
  delete test users anytime in the beta developer console to free up user slots.
</Note>

## Prerequisites

To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.

<Warning>
  Don't have an API key yet? Request access to the <Link label="Developer Portal" href="https://developer.getpara.com" /> to create API keys, manage billing, teams, and more.
</Warning>

<DemoCallout variant="subtle" />

Need to install the SDK? Start with the <Link label="Swift Setup Guide" href="/v3/swift/setup" />.

<Note>
  Para ships with One Click enabled. You can add requirements like Passkey-only signup or password fallback from the <Link label="Developer Portal" href="https://developer.getpara.com" />. Adjust the optional sections below only if you turn on those features.
</Note>

## Start the Authentication Flow

Inject the Para manager and authentication helpers, then launch the flow with whichever identifier your UI collects (email or phone). Para One Click handles the rest unless you enable extra verification.

```swift AuthenticationView.swift theme={null}
import AuthenticationServices
import ParaSwift

struct AuthenticationView: View {
    @EnvironmentObject var paraManager: ParaManager
    @Environment(\.authorizationController) private var authorizationController
    @Environment(\.webAuthenticationSession) private var webAuthenticationSession

    @State private var pendingState: AuthState? // Only used if you enable OTP/passkey requirements

    var body: some View {
        VStack {
            // Render your auth UI and call startAuth(identifier:)
        }
        .task {
            paraManager.setDefaultWebAuthenticationSession(webAuthenticationSession)
        }
    }

    private func startAuth(identifier: String) {
        let auth: Auth = identifier.contains("@")
            ? .email(identifier.lowercased())
            : .phone(identifier) // Expect E.164 format

        Task {
            do {
                let state = try await paraManager.initiateAuthFlow(auth: auth)

                switch state.stage {
                case .done:
                    completeLogin()
                case .verify:
                    // Store state to finish OTP/passkey signup later if you enabled it
                    pendingState = state
                case .login:
                    try await paraManager.handleLogin(
                        authState: state,
                        authorizationController: authorizationController
                    )
                    completeLogin()
                case .signup:
                    // Signup completes after OTP + passkey if required
                    break
                }
            } catch {
                // Handle errors according to your UI needs
            }
        }
    }
}
```

The `completeLogin()` helper can mark your app as authenticated and transition to the signed-in experience:

```swift AuthenticationView.swift theme={null}
private func completeLogin() {
    // Mark the user as authenticated in your app
}
```

## Handle OTP Signup (Optional)

Only implement this step if you turn on OTP / passkey signup in the Developer Portal. Collect the OTP, exchange it for a verified state, and finish signup:

```swift AuthenticationView.swift theme={null}
private func submitOtp(_ code: String) {
    guard let pendingState else { return }

    Task {
        do {
            let verifiedState = try await paraManager.handleVerificationCode(
                verificationCode: code
            )

            try await paraManager.handleSignup(
                authState: verifiedState,
                method: .passkey,
                authorizationController: authorizationController
            )

            completeLogin()
        } catch {
            // Handle errors according to your UI needs
        }
    }
}
```

<Note>
  If you skip `setDefaultWebAuthenticationSession(_:)`, `initiateAuthFlow` returns a `loginUrl` you can present manually using `presentAuthUrl(_:context:webAuthenticationSession:)`. The automatic `.done` stage shown above relies on the default session being set.
</Note>

## Support Direct Passkey Login

If you already know a user has passkeys registered, you can offer a shortcut that skips email/phone input:

```swift AuthenticationView.swift theme={null}
private func loginWithPasskey(email: String?) {
    Task {
        do {
            try await paraManager.loginWithPasskey(
                authorizationController: authorizationController,
                email: email,
                phone: nil
            )
            completeLogin()
        } catch {
            // Handle errors according to your UI needs
        }
    }
}
```

## Next Steps

* Add social providers alongside this flow in <Link label="Add Social Login" href="/v3/swift/guides/social-login" />
* Manage existing sessions with <Link label="Manage Sessions" href="/v3/swift/guides/sessions" />
