---
title: Authentication
description: Authenticate the Daytona SDKs, CLI, and API to create sandboxes.
---
Daytona authenticates SDK, CLI, and API requests with a project [API key](/docs/v2/api-keys). The key identifies the [project](/docs/v2/projects) that owns the sandboxes you create and carries the [permissions](/docs/v2/api-keys#permissions--scopes) a request may use.
## Get an API key
1. Go to [Daytona Dashboard ↗](https://app.daytona.com/dashboard/keys)
2. Click
3. Enter
4. Select permission
5. Click
6. Copy and save the API key as an environment variable
## Environment variables
Daytona resolves configuration in order of precedence:
1. Configuration in code
2. Environment variables
| **Variable** | **Description** |
| ------------------------- | ---------------------------------------------------------------------------------------------- |
| **`DAYTONA_API_KEY`** | Your Daytona API key. Required unless `DAYTONA_JWT_TOKEN` is set |
| **`DAYTONA_JWT_TOKEN`** | A JWT instead of an API key. Optional; needs `DAYTONA_PROJECT_ID` |
| **`DAYTONA_PROJECT_ID`** | The project a JWT is scoped to. Required with `DAYTONA_JWT_TOKEN` |
### .env
```bash
DAYTONA_API_KEY=YOUR_API_KEY
```
### Shell
```bash
export DAYTONA_API_KEY=YOUR_API_KEY
```
```powershell
$env:DAYTONA_API_KEY="YOUR_API_KEY"
```
## Authenticate the SDK
Construct the client without arguments to read the environment variables, or pass the configuration in code. Every call made through the client sends the API key or, with a JWT, a short-lived project token the client exchanges the JWT for.
```python
from daytona import Daytona, DaytonaConfig
# Using environment variables
daytona = Daytona()
# Using explicit configuration
config = DaytonaConfig(api_key="YOUR_API_KEY")
daytona = Daytona(config)
# Pick the region per create
sandbox = daytona.v2.create(region="us")
```
Each `DaytonaConfig` field falls back to its environment variable independently. The client has no API URL or region field: every create takes a `region`, and the API picks the project, organization, or platform default when it is omitted.
| **Parameter** | **Type** | **Description** |
| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api_key` | `str` | Falls back to `DAYTONA_API_KEY`. When neither this nor `jwt_token` is set, the client constructor raises `UnauthorizedError`. |
| `jwt_token` | `str` | A JWT instead of an API key. Falls back to `DAYTONA_JWT_TOKEN`. Needs `project_id`; setting both `api_key` and `jwt_token` raises `BadRequestError`. |
| `project_id` | `str` | The project a JWT is scoped to. Falls back to `DAYTONA_PROJECT_ID`. |
| `request_timeout` | `float` | Per-request HTTP timeout in seconds. `0` disables the timeout. |
```typescript
import { Daytona } from '@daytona/sdk'
// Using environment variables
const daytona = new Daytona()
// Using explicit configuration
const daytonaWithConfig = new Daytona({ apiKey: 'YOUR_API_KEY' })
// Pick the region per create
const sandbox = await daytonaWithConfig.v2.create({ region: 'us' })
```
Each `DaytonaConfig` field falls back to its environment variable independently. The client has no API URL or region field: every create takes a `region`, and the API picks the project, organization, or platform default when it is omitted.
| **Parameter** | **Type** | **Description** |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey` | `string` | Falls back to `DAYTONA_API_KEY`. When neither this nor `jwtToken` is set, the constructor throws `DaytonaAuthenticationError`. |
| `jwtToken` | `string` | A JWT instead of an API key. Falls back to `DAYTONA_JWT_TOKEN`. Needs `projectId`; setting both `apiKey` and `jwtToken` throws `DaytonaValidationError`. |
| `projectId` | `string` | The project a JWT is scoped to. Falls back to `DAYTONA_PROJECT_ID`. |
| `requestTimeout` | `number` | Per-request HTTP timeout in milliseconds. `0` disables the timeout. |
### Close the client
Close the client when your program no longer needs it. The client holds network resources between calls, such as the connection that reports sandbox state changes, and closing it releases them. Closing does not stop or delete any sandbox. Closing an already closed client does nothing.
```python
from daytona import Daytona
# Close the client when the block exits
with Daytona() as daytona:
sandbox = daytona.v2.create()
# Close the client explicitly
daytona = Daytona()
sandbox = daytona.v2.create()
daytona.close()
```
- Use `AsyncDaytona` with `async with` or `await daytona.close()` in asynchronous code.
- After `close()`, the next access to `daytona.v2` builds a new client.
```typescript
import { Daytona } from '@daytona/sdk'
const daytona = new Daytona()
const sandbox = await daytona.v2.create()
// Close the client explicitly
await daytona.close()
```
- Declare the client with `await using` to close it when the scope exits.
- After `close()`, the next access to `daytona.v2` builds a new client.
- An open client does not keep a Node.js process alive, so a short script can exit without closing it. Close it in long-running processes.
## Authenticate the CLI
Sign in once and the CLI saves the session in its active profile, so following commands need no key or flags. After a browser or device login, the CLI selects your personal organization and its default project the first time and remembers your last selection afterwards; sandbox commands then mint a short-lived project API key on your behalf, which expires with the session.
```bash
# Browser login
daytona login --api-url https://api.daytona.com
# Device-code login on a host without a browser
daytona login --device --api-url https://api.daytona.com
# Store an API key in the active profile
daytona login --token YOUR_API_KEY --api-url https://api.daytona.com
# Confirm who you are and what is selected
daytona whoami
# Create a sandbox with the saved session
daytona sandbox create
# Remove the saved session from this machine
daytona logout
```
```bash
# Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL)
daytona sandbox create
# Using explicit flags
daytona sandbox create --api-key YOUR_API_KEY --api-url https://api.daytona.com
```
| **Flag** | **Type** | **Description** |
| ----------- | -------- | ------------------------------------------------------------------------------------------------ |
| `--api-key` | `string` | Takes precedence over `DAYTONA_API_KEY`. Either one replaces the saved login for that command. |
| `--api-url` | `string` | Takes precedence over `DAYTONA_API_URL`, and either one overrides the URL stored in the profile. |
| `--profile` | `string` | Selects a profile other than the active one. `DAYTONA_PROFILE` does the same. |
## Authenticate API requests
Send the API key as a bearer token in the authorization header of every request.
```bash
curl 'https://api.daytona.com/sandboxes' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{}'
```
- Creating a sandbox needs the `write:sandboxes` permission.
- Creating a sandbox also needs the `read:secrets` permission when the request attaches secrets.