> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.ouster.com/sensor-docs/firmware/3.2/api-reference/ouster-http-api/authentication/get-auth-challenge/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ouster.com/_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 response = Unirest.get("http://os-992244000006.local/api/v1/auth/challenge") .asString(); ``` ```php 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() ```