> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ouster.com/sensor-docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ouster.com/sensor-docs/_mcp/server.

# Generate authentication challenge

GET http://os-992244000006.local/api/v1/auth/challenge

Public endpoint that generates a challenge for three-party JWT authentication.

**Security Notes:**
- Public endpoint, requires external rate limiting
- Nonce is single-use and expires based on JWT `exp_poh` claim
- Device stores up to 50 nonces with FIFO eviction

**Flow:**
1. Client calls this endpoint to get challenge
2. Client presents challenge to auth server with user credentials
3. Auth server issues JWT with nonce and expiration
4. Client submits JWT to `/auth/login` endpoint


Reference: https://docs.ouster.com/sensor-docs/firmware/3.2/api-reference/ouster-http-api/authentication/get-auth-challenge

## Response

### 200

Challenge generated successfully

- `sn` (string, required) — Device serial number (audience for JWT validation)
- `now_poh` (double, required) — Current power-on hours (for POH-based expiration)
- `nonce` (string, required) — 128-bit random nonce (base64url, 22 chars) for replay protection
- `fw` (string, required) — Firmware version (semver)

## Errors

### 500 Internal Server Error

Device serial number not available

- `title` (string, optional) — Error title
- `description` (string, optional) — Error description

## Examples

**Response**

```json
{
  "sn": "991900123456",
  "now_poh": 42.5,
  "nonce": "a1b2c3d4e5f6g7h8i9j0k1",
  "fw": "3.2.0"
}
```

**SDK Code**

```python
import requests

url = "http://os-992244000006.local/api/v1/auth/challenge"

response = requests.get(url)

print(response.json())
```

```javascript
const url = 'http://os-992244000006.local/api/v1/auth/challenge';
const options = {method: 'GET'};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "http://os-992244000006.local/api/v1/auth/challenge"

	req, _ := http.NewRequest("GET", url, nil)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("http://os-992244000006.local/api/v1/auth/challenge")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("http://os-992244000006.local/api/v1/auth/challenge")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'http://os-992244000006.local/api/v1/auth/challenge');

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("http://os-992244000006.local/api/v1/auth/challenge");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let request = NSMutableURLRequest(url: NSURL(string: "http://os-992244000006.local/api/v1/auth/challenge")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```