# Authentication

## Authenticate with Privy token

> Verify a Privy token and return the user's info including roles and a Meshmap session token. Creates a new user if one does not exist.

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"paths":{"/auth/privy":{"post":{"summary":"Authenticate with Privy token","description":"Verify a Privy token and return the user's info including roles and a Meshmap session token. Creates a new user if one does not exist.","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrivyAuthRequest"}}}},"responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrivyAuthResponse"}}}},"400":{"description":"Token is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Invalid token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"PrivyAuthRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Privy authentication token"}}},"PrivyAuthResponse":{"type":"object","required":["user","meshmapSessionToken"],"properties":{"user":{"type":"object","required":["id","email","firstName","lastName","roles","isAdmin","hasOpsAccess"],"properties":{"id":{"type":"string","description":"User ID"},"email":{"type":"string","nullable":true,"description":"User email"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"roles":{"type":"array","items":{"type":"string"},"description":"User roles"},"isAdmin":{"type":"boolean","description":"Whether the user has admin role"},"hasOpsAccess":{"type":"boolean","description":"Whether the user has ops or admin access"}}},"meshmapSessionToken":{"type":"string","description":"JWT session token for authenticating with Meshmap APIs"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}}}
```

## Get current user profile

> Get the profile information for the authenticated user

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"SessionToken":[]}],"components":{"securitySchemes":{"SessionToken":{"type":"apiKey","in":"header","name":"Authorization","description":"Session token in Bearer format: Bearer <token>"}},"schemas":{"UserSchema":{"type":"object","required":["id","createdAt"],"properties":{"id":{"type":"string","description":"Unique user identifier"},"email":{"type":"string","nullable":true,"description":"User email address"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number"},"username":{"type":"string","nullable":true,"description":"User username"},"createdAt":{"type":"string","format":"date-time","description":"User creation timestamp"},"imageUrl":{"type":"string","nullable":true,"description":"User profile image URL"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/user":{"get":{"summary":"Get current user profile","description":"Get the profile information for the authenticated user","tags":["Authentication"],"responses":{"200":{"description":"User profile retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"401":{"description":"Unauthorized - invalid or missing session token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Update current user profile

> Update the username for the authenticated user

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"SessionToken":[]}],"components":{"securitySchemes":{"SessionToken":{"type":"apiKey","in":"header","name":"Authorization","description":"Session token in Bearer format: Bearer <token>"}},"schemas":{"UserPatchRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string","minLength":1,"description":"New username for the user"}}},"UserSchema":{"type":"object","required":["id","createdAt"],"properties":{"id":{"type":"string","description":"Unique user identifier"},"email":{"type":"string","nullable":true,"description":"User email address"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number"},"username":{"type":"string","nullable":true,"description":"User username"},"createdAt":{"type":"string","format":"date-time","description":"User creation timestamp"},"imageUrl":{"type":"string","nullable":true,"description":"User profile image URL"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/user":{"patch":{"summary":"Update current user profile","description":"Update the username for the authenticated user","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPatchRequest"}}}},"responses":{"200":{"description":"User profile updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - invalid or missing session token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Username is already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Remove user profile image

> Delete the profile image for the authenticated user

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"SessionToken":[]}],"components":{"securitySchemes":{"SessionToken":{"type":"apiKey","in":"header","name":"Authorization","description":"Session token in Bearer format: Bearer <token>"}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/user/profile-image":{"delete":{"summary":"Remove user profile image","description":"Delete the profile image for the authenticated user","tags":["Authentication"],"responses":{"200":{"description":"Profile image removed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"description":"Unauthorized - invalid or missing session token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Upload user profile image

> Upload or replace the profile image for the authenticated user

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"SessionToken":[]}],"components":{"securitySchemes":{"SessionToken":{"type":"apiKey","in":"header","name":"Authorization","description":"Session token in Bearer format: Bearer <token>"}},"schemas":{"UserSchema":{"type":"object","required":["id","createdAt"],"properties":{"id":{"type":"string","description":"Unique user identifier"},"email":{"type":"string","nullable":true,"description":"User email address"},"firstName":{"type":"string","nullable":true,"description":"User first name"},"lastName":{"type":"string","nullable":true,"description":"User last name"},"phoneNumber":{"type":"string","nullable":true,"description":"User phone number"},"username":{"type":"string","nullable":true,"description":"User username"},"createdAt":{"type":"string","format":"date-time","description":"User creation timestamp"},"imageUrl":{"type":"string","nullable":true,"description":"User profile image URL"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/user/profile-image":{"patch":{"summary":"Upload user profile image","description":"Upload or replace the profile image for the authenticated user","tags":["Authentication"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["image"],"properties":{"image":{"type":"string","format":"binary","description":"Image file to upload"}}}}}},"responses":{"200":{"description":"Profile image uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"400":{"description":"Invalid image file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - invalid or missing session token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Generate authentication game code

> Generate a new 6-digit authentication code from headset side

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"AppAPIKey":[]}],"components":{"securitySchemes":{"AppAPIKey":{"type":"apiKey","in":"header","name":"x-app-api-key","description":"App API key in format: <key>"}},"schemas":{"CreateCodeRequest":{"type":"object","required":["playerId"],"properties":{"playerId":{"type":"string","description":"Player ID to associate with the code. Used to link the player to the code. Optional.","nullable":true}}},"CodeSchema":{"type":"object","required":["code","expiryTime"],"properties":{"code":{"type":"string","description":"Generated authentication code","pattern":"^[0-9]{6}$"},"playerId":{"type":"string","nullable":true,"description":"Player ID associated with the code (if provided)"},"expiryTime":{"type":"string","format":"date-time","description":"Code expiration timestamp"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/code":{"post":{"summary":"Generate authentication game code","description":"Generate a new 6-digit authentication code from headset side","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCodeRequest"}}}},"responses":{"200":{"description":"Code generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeSchema"}}}},"401":{"description":"Unauthorized - invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unable to generate unique code or internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Validate authentication code

> Validate an authentication code and optionally return a session token

```json
{"openapi":"3.0.0","info":{"title":"Meshmap API v1","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1 base URL"}],"security":[{"AppAPIKey":[]}],"components":{"securitySchemes":{"AppAPIKey":{"type":"apiKey","in":"header","name":"x-app-api-key","description":"App API key in format: <key>"}},"schemas":{"CreateTokenFromCodeRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Authentication code","pattern":"^[0-9]{6}$"}}},"CreateTokenFromCodeResponse":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["VALID","INVALID","EXPIRED","ERROR"],"description":"Code validation status"},"sessionToken":{"type":"string","description":"JWT session token (only present when status is VALID and user is authenticated)"},"expiryTime":{"type":"string","format":"date-time","description":"Code expiry time (only present when status is VALID)"},"error":{"type":"string","description":"Error message (only present when status is not VALID)"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"oneOf":[{"type":"string","description":"Error message"},{"type":"array","items":{"type":"object","required":["code","message","path"],"properties":{"code":{"type":"string","description":"Error code"},"message":{"type":"string","description":"Error message"},"path":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":"Error path"}}}}]}}}}},"paths":{"/auth/code":{"post":{"summary":"Validate authentication code","description":"Validate an authentication code and optionally return a session token","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTokenFromCodeRequest"}}}},"responses":{"200":{"description":"Game code validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTokenFromCodeResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - invalid or missing App API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```
