# SSO Login

> Authenticate users with their Bolt account via OAuth 2.0 and PKCE using the Bolt iOS SDK.

Source: https://help.boltapp.com/developers/sdks/ios-swift/sso-login

## Overview [#overview]

The Bolt iOS SDK provides a built-in SSO flow that lets users log in with their Bolt account using OAuth 2.0, and optionally PKCE. After login, you receive an authorization code and state that your **backend** exchanges for an access token.

<Note>
  If you don't have a backend application and need to exchange the authorization code directly from your mobile app, enable PKCE mode and send the authorization code, state, and code verifier to the Bolt token exchange endpoint.
</Note>

The SDK provides three approaches for starting the login flow, matching the checkout pattern:

| Approach               | Best For                                          |
| ---------------------- | ------------------------------------------------- |
| **Completion handler** | Simplest: works from anywhere, including SwiftUI. |
| **Delegate pattern**   | Callback-based, mirrors the Android SDK.          |
| **View controller**    | Full control over presentation.                   |

## Completion Handler [#completion-handler]

```swift title="Swift"
BoltCheckout.shared.startLogin { result in
    switch result {
    case .completed(let authorizationCode, let codeVerifier, let state):
        // Send authCode and state to YOUR backend for token exchange
        myBackendApi.exchangeBoltToken(authorizationCode, state)
    case .canceled:
        print("User canceled login")
    case .failed(let error):
        print("Login failed: \(error.localizedDescription)")
    }
}
```

## Delegate Pattern [#delegate-pattern]

Implement `BoltLoginDelegate` for callback-based results:

```swift title="Swift"
class LoginManager: BoltLoginDelegate {

    func startLogin() {
        BoltCheckout.shared.startLogin(delegate: self)
    }

    // --- BoltLoginDelegate callbacks ---

    func onLoginSuccess(authCode: String, codeVerifier: String, state: String) {
        // Send authCode and state to YOUR backend for token exchange.
        myBackendApi.exchangeBoltToken(authCode, state)
    }

    func onLoginError(errorReason: String) {
        // Login failed (e.g. network error, user denied permissions)
    }

    func onLoginCancel() {
        // User dismissed the login screen without completing
    }
}
```

## View Controller (Explicit Presentation) [#view-controller-explicit-presentation]

```swift title="Swift"
let loginVC = BoltLoginViewController(delegate: self)
present(loginVC, animated: true)
```

## PKCE Mode [#pkce-mode]

By default, the SDK does not include a PKCE code challenge in the authorization request. If your integration exchanges the authorization code directly from the client, enable PKCE:

```swift title="Swift"
let loginConfig = BoltLoginConfig(usePkce: true)

// Completion handler
BoltCheckout.shared.startLogin(loginConfig: loginConfig) { result in
    switch result {
    case .completed(let authorizationCode, let codeVerifier, let state):
        // codeVerifier is non-empty when usePkce is true
        // Send authorizationCode, codeVerifier, and state to token exchange endpoint
        ...
    case .canceled: break
    case .failed(let error): break
    }
}

// Or delegate
BoltCheckout.shared.startLogin(loginConfig: loginConfig, delegate: self)

// Or view controller
let loginVC = BoltLoginViewController(delegate: self, loginConfig: loginConfig)
present(loginVC, animated: true)
```

When `usePkce` is `false` (default), no `code_challenge` is sent and `codeVerifier` in the callback will be an empty string.

## How It Works [#how-it-works]

1. `startLogin()` opens a WebView with the Bolt-hosted login page. Your app does not pass an email: the user enters it directly on the page.
2. *(PKCE flow only)* The SDK generates a PKCE code verifier and code challenge automatically.
3. The user enters their Bolt account email. Bolt sends a one-time passcode (OTP) via email or SMS: the user picks their preferred delivery method and enters the code.
4. On success, the hosted page redirects with an authorization code.
5. The SDK intercepts this redirect inside the WebView: **no URL scheme configuration in your app is required**.
6. `onLoginSuccess(authCode:codeVerifier:state:)` is called.

## Backend Token Exchange [#backend-token-exchange]

When `onLoginSuccess` fires, send `authCode` to your backend immediately. Your backend exchanges it for an access token:

| Environment | Token Endpoint                                   |
| ----------- | ------------------------------------------------ |
| Sandbox     | `https://api-sandbox.boltapp.com/v1/oauth/token` |
| Production  | `https://api.boltapp.com/v1/oauth/token`         |

```http title="HTTP"
POST https://api.boltapp.com/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

client_id=<your-publishable-key>
&code=<authCode from onLoginSuccess>
&grant_type=authorization_code
&scope=openid bolt.account.manage
&state=<state from onLoginSuccess>
```

<Warning>
  Do not write `authCode` to persistent storage (UserDefaults, Keychain, or disk). Forward it to your backend directly from the completion handler and let it go out of scope.
</Warning>

## Logout [#logout]

To log the user out of their Bolt session:

```swift title="Swift"
BoltCheckout.shared.logOut()
```

## SFCC Integration [#sfcc-integration]

Some merchants use Salesforce Commerce Cloud (SFCC) as their e-commerce platform and have configured Bolt as an OAuth identity provider within SFCC. In this setup, the token exchange does **not** go directly to Bolt's `/v1/oauth/token` endpoint. Instead, the Bolt authorization code and state are forwarded to SFCC, which handles the token exchange server-to-server on your behalf.

<Note>
  In the SFCC flow, you should **not** use PKCE as the token exchange is made from your backend.
</Note>

### Key Differences from Standard SSO [#key-differences-from-standard-sso]

|                            | Standard Bolt SSO             | SFCC Integration                                           |
| -------------------------- | ----------------------------- | ---------------------------------------------------------- |
| Token exchange endpoint    | `POST /v1/oauth/token` (Bolt) | `Login-OAuthMobileBolt` → `Login-ExchangeSFCCToken` (SFCC) |
| `codeVerifier` usage       | Required only for PKCE flow   | Not used: discard after `onLoginSuccess`                   |
| Who calls Bolt's token API | Your backend                  | SFCC (server-to-server)                                    |
| Resulting token            | Bolt access token             | SFCC JWT bearer token                                      |

### SFCC Endpoint Reference [#sfcc-endpoint-reference]

| Step                | Method | URL                                                           |
| ------------------- | ------ | ------------------------------------------------------------- |
| Authorize           | `GET`  | `https://api-sandbox.boltapp.com/v1/oauth/internal/authorize` |
| SFCC code exchange  | `GET`  | `https://<sfcc-host>/.../Login-OAuthMobileBolt`               |
| SFCC token exchange | `POST` | `https://<sfcc-host>/.../Login-ExchangeSFCCToken`             |
