# Xcode 13.3 supports SPM binary dependency in private GitHub release

In this blog post I will share details about a new feature not mentioned in the [Xcode 13.3 Beta 3 release notes](https://developer.apple.com/documentation/Xcode-Release-Notes/xcode-13_3-release-notes). This feature is of interest to developers who need to make their code available as binaries to protect their intellectual property when developing proprietary, closed-source libraries. 

To distribute code in binary form as a Swift package, create an XCFramework bundle that contains the binaries. Then, make the bundle available locally or on a server. Here is an example of a `Package.swift` manifest to distribute a binary framework stored on a server:

```Swift
// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "MyLibrary",
    platforms: [
        .macOS(.v10_14), .iOS(.v13), .tvOS(.v13)
    ],
    products: [
        .library(
            name: "MyLibrary",
            targets: ["SomeRemoteBinaryPackage"])
    ],
    dependencies: [],
    targets: [
        .binaryTarget(
            name: "SomeRemoteBinaryPackage",
            url: "https://url/to/some/remote/xcframework.zip",
            checksum: "The checksum of the ZIP archive that contains the XCFramework."
        )
    ]
)
```

The xcframework.zip file needed to be publicly accessible on a server. But what if you need to limit public access to authenticated users? 

The `.netrc` file format is commonly used for the automatic authentication of HTTP requests. 

```bash
machine <example.com> login <my-user-name> password <my-password>
```

It generally resides in the user’s home directory (`~/.netrc`). Learn more about netrc by reading the [gnu documentation](https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html).

My former co-worker [Stan Stadelman](https://twitter.com/StadelmanStan) introduced `netrc` into SPM to support basic auth aiming non-git binary dependency hosts. 

%[https://github.com/apple/swift-package-manager/pull/2833]

The user is not required to opt-in to use netrc as the [option is turned on per default in the Swift Package Manager](https://github.com/apple/swift-package-manager/blob/5a94f3c4625158c4dd8da6c92b6800ce2cc0e1e7/Sources/Commands/Options.swift#L144).

```Swift
    /// Whether to load .netrc files for authenticating with remote servers
    /// when downloading binary artifacts or communicating with a registry.
    @Flag(inversion: .prefixedEnableDisable,
          exclusivity: .exclusive,
          help: "Load credentials from a .netrc file")
    var netrc: Bool = true
```

SPM will automatically detect the `.netrc` file and apply the required `Authentication` header. Also, with option `netrc-file <netrc-file>` you can specify a different location.

This feature became available with Xcode 12.5. However, the community pointed out that this does [not work for a private GitHub release](https://forums.swift.org/t/spm-binary-dependency-in-private-github-release/52514/3).

First, you cannot use the browser download URL as an HTTP request results in a 302 redirect. You have to [lookup the asset name](https://forums.swift.org/t/spm-support-basic-auth-for-non-git-binary-dependency-hosts/37878/35) and then use the asset url.
- Incorrect URL: `https://github.com/:owner/:repo/releases/download/:tag/some.xcframework.zip`
- Correct URL: `https://api.github.com/repos/:owner/:repo/releases/assets/\(assetId).zip`

But more importantly, there is another issue that SPM was not aware of.

```
// netrc support is NOT enough to make this work for a private repo asset
.binaryTarget(
    name: privateName,
    url: "https://api.github.com/repos/:owner/:repo/releases/assets/\(assetId).zip",
    checksum: checksum
)
```

The [Github API](https://docs.github.com/en/rest/reference/releases#get-a-release-asset) states the `Accept` header of the request to `application/octet-stream` is required to download the asset's binary content. Otherwise the API JSON response is returned.

Hence the following change was introduced in SPM, by [Jimmy Arts](https://medium.com/@jimmyarts), to set the header automatically:

%[https://github.com/apple/swift-package-manager/pull/3795]

Xcode 13.3 Beta 3 includes this change.  Hence, using Xcode 13.3 Beta 3 and a `.netrc` file with a GitHub personal access token will finally allow you to download binary assets from release in a private GitHub repository. 😊🎉

Example: I have a repository `MyPrivateRepo` under my GitHub user `MarcoEidinger` and I created release `1.0.0` with asset `MyBinaryModuleName.xcframework.zip`. Hence the `Package.swift` would be like

```Swift
.binaryTarget(
    name: "MyBinaryModuleName",
    url: "https://api.github.com/repos/MarcoEidinger/MyPrivateRepo/releases/assets/58858051.zip",
    checksum: "c533f08210ac21def782d48c2ff1e1a538b05b051e128aa88ffcd44051ddc2b3"
),
```

and my `~/.netrc` file would be something like

```bash
machine api.github.com login MarcoEidinger password ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

Netrc is a great solution which works on Mac and also on Linux. If you are exclusively working on Mac then you can leverage Apple's Keychain as alternative. Instead of creating an entry in the `~/.netrc` file you can create an internet password containing 
- `Keychain Item Name`: https://api.github.com
- `Account Name`: GitHub user name
- `Password`: personal access token

![New Password Item](https://cdn.hashnode.com/res/hashnode/image/upload/v1646781868323/Plql0J1ft.png)

![Create Internet Password](https://cdn.hashnode.com/res/hashnode/image/upload/v1646781889417/z6bT2DL_G.png)

Xcode (SPM) will read from keychain once you granted permission. Such a dialogue may come up during package resolution.

![Xcode requires permission to access keychain](https://cdn.hashnode.com/res/hashnode/image/upload/v1646782011502/7FhwkBUlI.png)

P.S.: The whole history can be traced in the following thread in the Swift Forum:

%[https://forums.swift.org/t/spm-support-basic-auth-for-non-git-binary-dependency-hosts/37878]


