> ## Documentation Index
> Fetch the complete documentation index at: https://tbd-6fc993ce-hypeship-docs-website-deploy-hook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Credentials

> Automate authentication with stored credentials

Credentials allow you to store login information securely and enable Kernel's automated re-authentication without requiring user interaction.

**There are three ways to provide credentials:**

* **Automatically save during login** — Capture credentials directly from the user when they log in via [Hosted UI](/auth/hosted-ui) or [Programmatic](/auth/programmatic)
* **Pre-store in Kernel** — Create credentials before any login for fully headless automation
* **Connect 1Password** — Use credentials from your existing 1Password vaults

<Card title="1Password Integration" icon="key" href="/integrations/1password">
  Connect your 1Password vaults to automatically use existing credentials with Managed Auth. Credentials are automatically matched by domain.
</Card>

## Save credentials during login

By default, credentials entered during login are automatically saved for re-authentication. No extra parameters are needed:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const login = await kernel.auth.connections.login(auth.id);
  ```

  ```python Python theme={null}
  login = await kernel.auth.connections.login(auth.id)
  ```

  ```go Go theme={null}
  login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
  if err != nil {
  	panic(err)
  }
  _ = login
  ```
</CodeGroup>

Once saved, browser profiles stay authenticated automatically. When the session expires, Kernel re-authenticates using the stored credentials. Credentials are updated after every successful login. One-time codes (TOTP, SMS, etc.) are not saved.

To opt out of credential saving, set `save_credentials: false` when creating the connection:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const auth = await kernel.auth.connections.create({
    domain: 'example.com',
    profile_name: 'my-profile',
    save_credentials: false,
  });
  ```

  ```python Python theme={null}
  auth = await kernel.auth.connections.create(
      domain="example.com",
      profile_name="my-profile",
      save_credentials=False,
  )
  ```

  ```go Go theme={null}
  auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
  	ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
  		Domain:          "example.com",
  		ProfileName:     "my-profile",
  		SaveCredentials: kernel.Bool(false),
  	},
  })
  if err != nil {
  	panic(err)
  }
  _ = auth
  ```
</CodeGroup>

## Pre-store credentials

For fully automated flows where no user is involved, create credentials upfront:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const credential = await kernel.credentials.create({
    name: 'my-netflix-login',
    domain: 'netflix.com',
    values: {
      email: 'user@netflix.com',
      password: 'secretpassword123',
    },
  });
  ```

  ```python Python theme={null}
  credential = await kernel.credentials.create(
      name="my-netflix-login",
      domain="netflix.com",
      values={
          "email": "user@netflix.com",
          "password": "secretpassword123",
      },
  )
  ```

  ```go Go theme={null}
  credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
  	CreateCredentialRequest: kernel.CreateCredentialRequestParam{
  		Name:   "my-netflix-login",
  		Domain: "netflix.com",
  		Values: map[string]string{
  			"email":    "user@netflix.com",
  			"password": "secretpassword123",
  		},
  	},
  })
  if err != nil {
  	panic(err)
  }
  _ = credential
  ```
</CodeGroup>

Then link the credential when creating a connection:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const auth = await kernel.auth.connections.create({
    domain: 'netflix.com',
    profile_name: 'my-profile',
    credential: { name: credential.name },
  });

  // Start login - authenticates automatically using stored credentials
  const login = await kernel.auth.connections.login(auth.id);
  ```

  ```python Python theme={null}
  auth = await kernel.auth.connections.create(
      domain="netflix.com",
      profile_name="my-profile",
      credential={"name": credential.name},
  )

  # Start login - authenticates automatically using stored credentials
  login = await kernel.auth.connections.login(auth.id)
  ```

  ```go Go theme={null}
  auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
  	ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
  		Domain:      "netflix.com",
  		ProfileName: "my-profile",
  		Credential: kernel.ManagedAuthCreateRequestCredentialParam{
  			Name: kernel.String(credential.Name),
  		},
  	},
  })
  if err != nil {
  	panic(err)
  }

  // Start login - authenticates automatically using stored credentials
  login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
  if err != nil {
  	panic(err)
  }
  _ = login
  ```
</CodeGroup>

### 2FA with TOTP

For sites with authenticator app 2FA, include `totp_secret` to fully automate login:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const credential = await kernel.credentials.create({
    name: 'my-login',
    domain: 'github.com',
    values: {
      username: 'my-username',
      password: 'my-password',
    },
    totp_secret: 'JBSWY3DPEHPK3PXP',  // From authenticator app setup
  });
  ```

  ```python Python theme={null}
  credential = await kernel.credentials.create(
      name="my-login",
      domain="github.com",
      values={
          "username": "my-username",
          "password": "my-password",
      },
      totp_secret="JBSWY3DPEHPK3PXP",  # From authenticator app setup
  )
  ```

  ```go Go theme={null}
  credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
  	CreateCredentialRequest: kernel.CreateCredentialRequestParam{
  		Name:   "my-login",
  		Domain: "github.com",
  		Values: map[string]string{
  			"username": "my-username",
  			"password": "my-password",
  		},
  		TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"), // From authenticator app setup
  	},
  })
  if err != nil {
  	panic(err)
  }
  _ = credential
  ```
</CodeGroup>

### SSO / OAuth

For sites with "Sign in with Google/GitHub/Microsoft", set `sso_provider` and Kernel automatically clicks the matching SSO button and completes OAuth.

Common SSO provider domains (Google, Microsoft, Okta, Auth0, GitHub, etc.) are automatically allowed — you don't need to add them to `allowed_domains`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const credential = await kernel.credentials.create({
    name: 'my-google-login',
    domain: 'accounts.google.com',
    sso_provider: 'google',
    values: {
      email: 'user@gmail.com',
      password: 'password',
    },
  });

  const auth = await kernel.auth.connections.create({
    domain: 'target-site.com',
    profile_name: 'my-profile',
    credential: { name: credential.name },
  });
  ```

  ```python Python theme={null}
  credential = await kernel.credentials.create(
      name="my-google-login",
      domain="accounts.google.com",
      sso_provider="google",
      values={
          "email": "user@gmail.com",
          "password": "password",
      },
  )

  auth = await kernel.auth.connections.create(
      domain="target-site.com",
      profile_name="my-profile",
      credential={"name": credential.name},
  )
  ```

  ```go Go theme={null}
  credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
  	CreateCredentialRequest: kernel.CreateCredentialRequestParam{
  		Name:        "my-google-login",
  		Domain:      "accounts.google.com",
  		SSOProvider: kernel.String("google"),
  		Values: map[string]string{
  			"email":    "user@gmail.com",
  			"password": "password",
  		},
  	},
  })
  if err != nil {
  	panic(err)
  }

  auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
  	ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
  		Domain:      "target-site.com",
  		ProfileName: "my-profile",
  		Credential: kernel.ManagedAuthCreateRequestCredentialParam{
  			Name: kernel.String(credential.Name),
  		},
  	},
  })
  if err != nil {
  	panic(err)
  }
  _ = auth
  ```
</CodeGroup>

## Partial Credentials

Credentials don't need to contain every field required by the login form. You can store what you have and collect the necessary fields from the user. `auth.connections.login()` pauses for missing values.

As an example, the below credential has email + TOTP secret stored (and automatically handled), but no password. The password is dynamically collected from the user using Kernel's Hosted UI or your Programmatic flow:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const credential = await kernel.credentials.create({
    name: 'my-login',
    domain: 'example.com',
    values: { email: 'user@example.com' },  // No password
    totp_secret: 'JBSWY3DPEHPK3PXP',
  });

  const auth = await kernel.auth.connections.create({
    domain: 'example.com',
    profile_name: 'my-profile',
    credential: { name: credential.name },
  });

  const login = await kernel.auth.connections.login(auth.id);

  // Poll until password is needed
  let state = await kernel.auth.connections.retrieve(auth.id);
  while (state.flow_status === 'IN_PROGRESS') {
    if (state.flow_step === 'AWAITING_INPUT' && state.discovered_fields?.length) {
      // Only password field will be pending (email auto-filled from credential)
      await kernel.auth.connections.submit(auth.id, {
        fields: { password: 'user-provided-password' }
      });
    }
    await new Promise(r => setTimeout(r, 2000));
    state = await kernel.auth.connections.retrieve(auth.id);
  }
  // TOTP auto-submitted from credential → SUCCESS
  ```

  ```python Python theme={null}
  credential = await kernel.credentials.create(
      name="my-login",
      domain="example.com",
      values={"email": "user@example.com"},  # No password
      totp_secret="JBSWY3DPEHPK3PXP",
  )

  auth = await kernel.auth.connections.create(
      domain="example.com",
      profile_name="my-profile",
      credential={"name": credential.name},
  )

  login = await kernel.auth.connections.login(auth.id)

  # Poll until password is needed
  state = await kernel.auth.connections.retrieve(auth.id)
  while state.flow_status == "IN_PROGRESS":
      if state.flow_step == "AWAITING_INPUT" and state.discovered_fields:
          # Only password field will be pending (email auto-filled from credential)
          await kernel.auth.connections.submit(
              auth.id,
              fields={"password": "user-provided-password"},
          )
      await asyncio.sleep(2)
      state = await kernel.auth.connections.retrieve(auth.id)
  # TOTP auto-submitted from credential → SUCCESS
  ```

  ```go Go theme={null}
  credential, err := client.Credentials.New(ctx, kernel.CredentialNewParams{
  	CreateCredentialRequest: kernel.CreateCredentialRequestParam{
  		Name:   "my-login",
  		Domain: "example.com",
  		Values: map[string]string{
  			"email": "user@example.com", // No password
  		},
  		TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"),
  	},
  })
  if err != nil {
  	panic(err)
  }

  auth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
  	ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
  		Domain:      "example.com",
  		ProfileName: "my-profile",
  		Credential: kernel.ManagedAuthCreateRequestCredentialParam{
  			Name: kernel.String(credential.Name),
  		},
  	},
  })
  if err != nil {
  	panic(err)
  }

  login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
  if err != nil {
  	panic(err)
  }
  _ = login

  // Poll until password is needed
  state, err := client.Auth.Connections.Get(ctx, auth.ID)
  if err != nil {
  	panic(err)
  }
  for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
  	if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingInput && len(state.DiscoveredFields) > 0 {
  		// Only password field will be pending (email auto-filled from credential)
  		_, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
  			SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
  				Fields: map[string]string{"password": "user-provided-password"},
  			},
  		})
  		if err != nil {
  			panic(err)
  		}
  	}

  	time.Sleep(2 * time.Second)
  	state, err = client.Auth.Connections.Get(ctx, auth.ID)
  	if err != nil {
  		panic(err)
  	}
  }
  // TOTP auto-submitted from credential → SUCCESS
  ```
</CodeGroup>

This is useful when you want to:

* Store TOTP secrets but have users enter their password each time
* Pre-fill username/email but collect password at runtime
* Merge user-provided values into an existing credential automatically on successful login

## Security

| Feature                | Description                                          |
| ---------------------- | ---------------------------------------------------- |
| **Encrypted at rest**  | Values encrypted using per-organization keys         |
| **Write-only**         | Values cannot be retrieved via API after creation    |
| **Never logged**       | Values are never written to logs                     |
| **Never shared**       | Values are never passed to LLMs                      |
| **Isolated execution** | Authentication runs in isolated browser environments |

## Notes

* The `values` object is flexible and can be used to store whatever fields the login form needs (`email`, `username`, `company_id`, etc.)
* Deleting a credential unlinks it from associated connections so they can no longer auto-authenticate
* Use one credential per account. We recommend creating separate credentials for different user accounts
