# Workload Clientless Access to SaaS APIs with Go SDK

> Octelium documentation. Canonical page: <https://octelium.com/docs/octelium/latest/management/guide/service/http/api-clientless-go>.

You can easily protect all your public SaaS APIs as Octelium *Services* and provide your clientless `WORKLOAD` *Users* such as your Golang-based microservices and applications with secretless access to all of your APIs without having to expose, manage and share the API keys, access tokens or OAuth2 client credentials required to access such APIs. In this short guide, we're going to use the Golang SDK (read more [here](https://octelium.com/docs/octelium/latest/management/guide/sdk.md)) to access a generic HTTP SaaS API that requires a bearer access token.

We first create a *Secret* with the name `apikey1` that stores the bearer access token required to access the protected SaaS API as follows:

```bash
octeliumctl create secret apikey1
```

You can read more about *Secret* management [here](https://octelium.com/docs/octelium/latest/management/core/secret.md). Note that Octelium supports more HTTP authentication types other than bearer authentication. You can read more [here](https://octelium.com/docs/octelium/latest/management/core/service/http.md#secretless-access).

Now we actually create the *Service* representing our SaaS API as follows:

```yaml
kind: Service
metadata:
  name: my-api
spec:
  mode: HTTP
  isPublic: true
  config:
    upstream:
      url: https://api.example.com
    http:
      auth:
        bearer:
          fromSecret: apikey1
```

You can now apply the *Service* as follows (read more [here](https://octelium.com/docs/octelium/latest/management/core/overview.md)):

```bash
octeliumctl apply /PATH/TO/SERVICE.YAML
```

Now we need a *Credential* for the `WORKLOAD` *User* representing our application, which we name here `microservice1`. We create an authentication token *Credential* whose *Sessions* are `CLIENTLESS` (read more about authentication token *Credentials* [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#authentication-tokens) and *Session* types [here](https://octelium.com/docs/octelium/latest/management/core/credential.md#session-type)) as follows:

```bash
octeliumctl create cred --user microservice1 --session-type clientless microservice1-cred

# The output should be something like
Authentication Token: AQpA0f-8AQE2SLLZG3UDvvi...
```

Now, we add the `octelium-go` library to our Golang-based application as follows:

```bash
go get github.com/octelium/octelium/octelium-go
```

And we can now use it to access the *Service* `my-api` as follows:

```go
package main

import (
	"context"
	"fmt"
	"io"
	"os"

	octelium "github.com/octelium/octelium/octelium-go"
)

func main() {
	if err := run(context.Background()); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(ctx context.Context) error {
	client, err := octelium.New(ctx,
		octelium.WithDomain("example.com"),
		octelium.WithAuthenticator(
			octelium.AuthenticationToken(os.Getenv("OCTELIUM_AUTH_TOKEN")),
		),
	)
	if err != nil {
		return err
	}
	defer client.Close()

	httpClient := client.HTTPClient()

	resp, err := httpClient.Get("https://my-api.example.com/v1/resources")
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	fmt.Printf("Status: %s\nBody: %s\n", resp.Status, body)

	return nil
}
```

The `HTTPClient()` method returns a standard `*http.Client` that attaches the *Session* access token to every request. The access token is obtained upon the first request and automatically refreshed before it expires, so your application does not have to worry about periodically re-authenticating the *Session*. By default, the access token is only attached to HTTPS requests to the *Cluster* domain and its subdomains, so a redirect or a misconfigured URL cannot leak it to a third party.

You can also use `HTTPTransport()` to embed the authenticated transport in your own `http.Client`, or `TokenSource()` to use the *Session* access token with any library that accepts an `oauth2.TokenSource`.

> **Note:**
>
> You can also omit the options and let `octelium.New()` read the *Cluster* domain and the authentication token from the `OCTELIUM_DOMAIN` and `OCTELIUM_AUTH_TOKEN` environment variables respectively.

An authentication token is treated as a one-time credential. The library keeps refreshing the resulting *Session* but it does not reuse the authentication token to create a new *Session* once the current one can no longer be refreshed. For long-running workloads, you might want to use secretless OIDC assertions instead as shown below.

## Secretless Authentication via OIDC Assertions

Instead of issuing and distributing authentication tokens, workloads that already have OIDC identity tokens issued by the platform hosting them (e.g. Kubernetes service accounts, GitHub Actions, Azure, etc...) can use them to authenticate themselves to the *Cluster* via an OIDC assertion *IdentityProvider* (read more [here](https://octelium.com/docs/octelium/latest/management/core/identity-providers.md#oidc-assertion)). You only need to replace the authenticator as follows:

```go
client, err := octelium.New(ctx,
	octelium.WithDomain("example.com"),
	octelium.WithAuthenticator(
		// !mark
		octelium.AssertionFromFile("/var/run/secrets/octelium/token"),
	),
)
```

`AssertionFromFile()` reads the assertion upon every authentication, which makes it suitable for tokens that are periodically rotated by the platform such as Kubernetes projected service account tokens. Since a fresh assertion is used every time, the library also creates a new *Session* automatically whenever the previous one expires. You can also set the `OCTELIUM_ASSERTION_FILE` environment variable instead. You can see a complete example for workloads running inside Kubernetes clusters [here](https://octelium.com/docs/octelium/latest/management/guide/service/http/k8s-clientless.md#secretless-authentication-via-oidc-assertions).

It's important to note that the Go SDK is not the only way to access publicly exposed BeyondCorp *Services*. You can also use the OAuth2 client credentials flow to access any such *Service* (read more [here](https://octelium.com/docs/octelium/latest/user/clientless/oauth2.md)). This enables your applications and microservices written in any language to access the *Cluster*'s *Services* via standard OAuth2 libraries that are supported in most major programming languages without having to use any clients or use specific SDKs. For Rust applications, the `octelium` crate provides an equivalent HTTP client via `Client::http()` (read more about the SDKs [here](https://octelium.com/docs/octelium/latest/management/guide/sdk.md)).
