# Users

## List users or lookup by GitHub username/email

> Three modes of operation:\
> &#x20;       \
> &#x20;       \*\*Lookup by GitHub\*\* (when lookup=github):\
> &#x20;       \- Resolves a GitHub username to user profile\
> &#x20;       \- Use: GET /users?lookup=github\&id=\<username>\
> &#x20;       \- Returns full user profile or 404 if not found\
> &#x20;       \
> &#x20;       \*\*Lookup by Email\*\* (when lookup=email):\
> &#x20;       \- Looks up user by email address\
> &#x20;       \- Use: GET /users?lookup=email\&id=\<email>\
> &#x20;       \- Returns full user profile or 404 if not found\
> &#x20;       \
> &#x20;       \*\*List mode\*\* (default):\
> &#x20;       \- Retrieves a paginated list of users\
> &#x20;       \- Can filter by team (using team slug) or role\
> &#x20;       \- Returns user details including email, role, team memberships

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"UserDto":{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]},"teams":{"description":"Team details the user belongs to","type":"array","items":{"type":"string"}},"authData":{"type":"object","description":"Full Supabase auth user data"}},"required":["id","firstName","lastName","email","role"]}}},"paths":{"/sfp/api/users":{"get":{"operationId":"UsersController_listUsers","summary":"List users or lookup by GitHub username/email","description":"Three modes of operation:\n        \n        **Lookup by GitHub** (when lookup=github):\n        - Resolves a GitHub username to user profile\n        - Use: GET /users?lookup=github&id=<username>\n        - Returns full user profile or 404 if not found\n        \n        **Lookup by Email** (when lookup=email):\n        - Looks up user by email address\n        - Use: GET /users?lookup=email&id=<email>\n        - Returns full user profile or 404 if not found\n        \n        **List mode** (default):\n        - Retrieves a paginated list of users\n        - Can filter by team (using team slug) or role\n        - Returns user details including email, role, team memberships","parameters":[{"name":"lookup","required":false,"in":"query","description":"Lookup mode","schema":{"enum":["github","email"],"type":"string"}},{"name":"id","required":false,"in":"query","description":"Identifier for lookup (GitHub username or email)","schema":{"type":"string"}},{"name":"team","required":false,"in":"query","description":"Team slug to filter by","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Number of records to skip","schema":{"type":"number"}},{"name":"role","required":false,"in":"query","description":"Filter by role","schema":{"enum":["owner","member"],"type":"string"}}],"responses":{"200":{"description":"Users retrieved successfully or lookup successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDto"}}}},"400":{"description":"Bad request - missing id parameter for lookup"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: owner, member, application"},"404":{"description":"User not found (lookup mode only)"}},"tags":["Users"]}}}}
```

## Create a new user in a team

> Creates a new user account and adds them to the specified team. This endpoint:\
> &#x20;       \- Creates the user in the authentication system\
> &#x20;       \- Assigns the specified role (owner, member, or application)\
> &#x20;       \- Associates the user with the team\
> &#x20;       \- Sends a welcome email with login instructions\
> &#x20;       \
> &#x20;       Only users with owner role can create new users. The email must be unique across the system. If the user already exists in another team, they will be added to the specified team with the given role.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"team":{"type":"string","description":"Team identifier (slug) to add the user to"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"],"default":"member"},"ssoProviderId":{"type":"string","description":"SSO provider ID override (format: sso:<uuid>). If not provided, falls back to AUTH_SSO_PROVIDER_ID env var. When set, the user is created as an SSO user instead of email/password."}},"required":["firstName","lastName","email","team","role"]},"CreateUserResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the operation was successful"},"userId":{"type":"string","description":"ID of the created/existing user"},"teamAccountId":{"type":"string","description":"ID of the team account"},"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"team":{"type":"string","description":"Team identifier (slug)"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]},"isExistingUser":{"type":"boolean","description":"Whether the user already existed in the system"},"error":{"type":"string","description":"Error message if operation failed"}},"required":["success"]}}},"paths":{"/sfp/api/users":{"post":{"operationId":"UsersController_createUser","summary":"Create a new user in a team","description":"Creates a new user account and adds them to the specified team. This endpoint:\n        - Creates the user in the authentication system\n        - Assigns the specified role (owner, member, or application)\n        - Associates the user with the team\n        - Sends a welcome email with login instructions\n        \n        Only users with owner role can create new users. The email must be unique across the system. If the user already exists in another team, they will be added to the specified team with the given role.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserResponse"}}}},"403":{"description":"Forbidden - Requires role: owner"}},"tags":["Users"]}}}}
```

## Delete a user from a team

> Removes a user from a team or from all teams. This endpoint:\
> &#x20;       \- Removes the user's team membership(s)\
> &#x20;       \- Revokes access to team resources\
> &#x20;       \- Optionally removes from all teams if no team is specified\
> &#x20;       \- Does not delete the user account itself (user can still log in but won't have team access)\
> &#x20;       \
> &#x20;       Only users with owner role can delete users. Users cannot delete themselves. If removing from all teams, the user effectively loses all access to the system.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"DeleteUserDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address of the user to remove"},"team":{"type":"string","description":"Team identifier (slug) to remove the user from. If not provided, user will be removed from all teams."}},"required":["email"]},"DeleteUserResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the operation was successful"},"email":{"type":"string","description":"Email address of the user that was removed"},"team":{"type":"string","description":"Team identifier (slug) the user was removed from"},"userId":{"type":"string","description":"User ID that was removed"},"teamAccountId":{"type":"string","description":"Team account ID the user was removed from"},"error":{"type":"string","description":"Error message if operation failed"}},"required":["success"]}}},"paths":{"/sfp/api/users":{"delete":{"operationId":"UsersController_deleteUser","summary":"Delete a user from a team","description":"Removes a user from a team or from all teams. This endpoint:\n        - Removes the user's team membership(s)\n        - Revokes access to team resources\n        - Optionally removes from all teams if no team is specified\n        - Does not delete the user account itself (user can still log in but won't have team access)\n        \n        Only users with owner role can delete users. Users cannot delete themselves. If removing from all teams, the user effectively loses all access to the system.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteUserDto"}}}},"responses":{"200":{"description":"User deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteUserResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteUserResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteUserResponse"}}}},"403":{"description":"Forbidden - Requires role: owner"}},"tags":["Users"]}}}}
```

## Get current user profile

> Retrieves the complete profile of the currently authenticated user. Returns:\
> &#x20;       \- User identification (ID, email)\
> &#x20;       \- Account details and role\
> &#x20;       \- Team memberships\
> &#x20;       \- Authentication metadata (first name, last name)\
> &#x20;       \- JWT token information if available\
> &#x20;       \
> &#x20;       This endpoint is useful for applications to understand the current user's permissions and profile after authentication.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"UserDto":{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]},"teams":{"description":"Team details the user belongs to","type":"array","items":{"type":"string"}},"authData":{"type":"object","description":"Full Supabase auth user data"}},"required":["id","firstName","lastName","email","role"]}}},"paths":{"/sfp/api/users/me":{"get":{"operationId":"UsersController_getCurrentUser","summary":"Get current user profile","description":"Retrieves the complete profile of the currently authenticated user. Returns:\n        - User identification (ID, email)\n        - Account details and role\n        - Team memberships\n        - Authentication metadata (first name, last name)\n        - JWT token information if available\n        \n        This endpoint is useful for applications to understand the current user's permissions and profile after authentication.","parameters":[],"responses":{"200":{"description":"User profile retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDto"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: owner, member, application"}},"tags":["Users"]}}}}
```

## Get user by email

> Retrieves detailed information about a specific user by their email address. \
> &#x20;       \
> &#x20;       Access control:\
> &#x20;       \- Self-lookup: Users can always retrieve their own full profile\
> &#x20;       \- Owner lookup: Owners can view other users but receive limited data (no sensitive auth metadata)\
> &#x20;       \- Team-specific lookup: Optionally filter by team using the team slug parameter\
> &#x20;       \
> &#x20;       Returns user profile including account details, team memberships, and appropriate metadata based on access level.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"UserDto":{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]},"teams":{"description":"Team details the user belongs to","type":"array","items":{"type":"string"}},"authData":{"type":"object","description":"Full Supabase auth user data"}},"required":["id","firstName","lastName","email","role"]}}},"paths":{"/sfp/api/users/{email}":{"get":{"operationId":"UsersController_getUserByEmail","summary":"Get user by email","description":"Retrieves detailed information about a specific user by their email address. \n        \n        Access control:\n        - Self-lookup: Users can always retrieve their own full profile\n        - Owner lookup: Owners can view other users but receive limited data (no sensitive auth metadata)\n        - Team-specific lookup: Optionally filter by team using the team slug parameter\n        \n        Returns user profile including account details, team memberships, and appropriate metadata based on access level.","parameters":[{"name":"email","required":true,"in":"path","description":"User email","schema":{"type":"string"}},{"name":"team","required":false,"in":"query","description":"Team slug (optional for self-lookups)","schema":{"type":"string"}}],"responses":{"200":{"description":"User profile retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDto"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: owner, member, application"},"404":{"description":"User not found"}},"tags":["Users"]}}}}
```

## Update user details

> Updates user profile information. Users can update:\
> &#x20;       \- Their own profile (self-update)\
> &#x20;       \- Other users' profiles if they have owner role\
> &#x20;       \
> &#x20;       Updatable fields include:\
> &#x20;       \- User metadata (first name, last name)\
> &#x20;       \- Role assignments within teams\
> &#x20;       \- Team associations\
> &#x20;       \
> &#x20;       The endpoint validates permissions and ensures users cannot escalate their own privileges. Returns the updated user profile on success.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"UpdateUserDto":{"type":"object","properties":{"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]}}},"UpdateUserResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the operation was successful"},"user":{"description":"Updated user information","allOf":[{"$ref":"#/components/schemas/UserDto"}]},"error":{"type":"string","description":"Error message if operation failed"}},"required":["success"]},"UserDto":{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"firstName":{"type":"string","description":"First name of the user"},"lastName":{"type":"string","description":"Last name of the user"},"email":{"type":"string","description":"Email address of the user"},"role":{"type":"string","description":"Role of the user in the team","enum":["owner","member"]},"teams":{"description":"Team details the user belongs to","type":"array","items":{"type":"string"}},"authData":{"type":"object","description":"Full Supabase auth user data"}},"required":["id","firstName","lastName","email","role"]}}},"paths":{"/sfp/api/users/{email}":{"put":{"operationId":"UsersController_updateUser","summary":"Update user details","description":"Updates user profile information. Users can update:\n        - Their own profile (self-update)\n        - Other users' profiles if they have owner role\n        \n        Updatable fields include:\n        - User metadata (first name, last name)\n        - Role assignments within teams\n        - Team associations\n        \n        The endpoint validates permissions and ensures users cannot escalate their own privileges. Returns the updated user profile on success.","parameters":[{"name":"email","required":true,"in":"path","description":"User email","schema":{"type":"string"}},{"name":"team","required":false,"in":"query","description":"Team slug (optional)","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"User not found"}},"tags":["Users"]}}}}
```

## Refresh an OAuth provider token

> Exchanges a provider refresh token for a fresh access token.\
> \
> &#x20;       Supabase Auth does not automatically refresh OAuth provider tokens (GitHub, Azure DevOps).\
> &#x20;       This endpoint uses the server's OAuth app credentials to call the provider's token refresh\
> &#x20;       endpoint, returning a fresh access token to the caller.\
> \
> &#x20;       \- \*\*GitHub\*\*: Uses GITHUB\_OAUTH\_CLIENT\_ID/SECRET environment variables\
> &#x20;       \- \*\*Azure DevOps\*\*: Uses service principal credentials from the integrations table

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"RefreshProviderTokenDto":{"type":"object","properties":{"provider":{"type":"string","description":"OAuth provider whose token should be refreshed","enum":["github","azuredevops"]},"refresh_token":{"type":"string","description":"The provider refresh token obtained during OAuth login"}},"required":["provider","refresh_token"]},"RefreshProviderTokenResponseDto":{"type":"object","properties":{"access_token":{"type":"string","description":"Fresh provider access token"},"expires_in":{"type":"number","description":"Token lifetime in seconds"},"refresh_token":{"type":"string","description":"New refresh token (may rotate)"},"token_type":{"type":"string","description":"Token type (usually \"bearer\")"}},"required":["access_token","token_type"]}}},"paths":{"/sfp/api/users/refresh-provider-token":{"post":{"operationId":"UsersController_refreshProviderToken","summary":"Refresh an OAuth provider token","description":"Exchanges a provider refresh token for a fresh access token.\n\n        Supabase Auth does not automatically refresh OAuth provider tokens (GitHub, Azure DevOps).\n        This endpoint uses the server's OAuth app credentials to call the provider's token refresh\n        endpoint, returning a fresh access token to the caller.\n\n        - **GitHub**: Uses GITHUB_OAUTH_CLIENT_ID/SECRET environment variables\n        - **Azure DevOps**: Uses service principal credentials from the integrations table","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshProviderTokenDto"}}}},"responses":{"200":{"description":"Token refreshed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshProviderTokenResponseDto"}}}},"400":{"description":"Invalid refresh token or provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: owner, member"}},"tags":["Users"]}}}}
```
