diff --git a/docs/source/_static/rest-api.yml b/docs/source/_static/rest-api.yml index c7032bfb..e0d9fa24 100644 --- a/docs/source/_static/rest-api.yml +++ b/docs/source/_static/rest-api.yml @@ -1,89 +1,18 @@ -# see me at: https://jupyterhub.readthedocs.io/en/latest/reference/rest-api.html -swagger: "2.0" +openapi: 3.0.3 +# note: 3.1.0 required for requestBody on DELETE +# which we should maybe move away from info: title: JupyterHub description: The REST API for JupyterHub - # version should match jupyterhub/_version.py - # `make scopes` ensures this is in sync - version: 2.0.0rc3 license: name: BSD-3-Clause -schemes: [http, https] -securityDefinitions: - token: - type: apiKey - name: Authorization - in: header - oauth2: - type: oauth2 - flow: accessCode - # these must be absolute until we update to openapi 3 - authorizationUrl: "https://hub.example/hub/api/oauth2/authorize" - tokenUrl: "https://hub.example/hub/api/oauth2/token" - scopes: # Generated based on scope table in jupyterhub/scopes.py - (no_scope): Identify the owner of the requesting entity. - self: - The user’s own resources _(metascope for users, resolves to (no_scope) - for services)_ - inherit: - Everything that the token-owning entity can access _(metascope for - tokens)_ - admin:users: - Read, write, create and delete users and their authentication state, - not including their servers or tokens. - admin:auth_state: Read a user’s authentication state. - users: - Read and write permissions to user models (excluding servers, tokens - and authentication state). - delete:users: Delete users. - list:users: List users, including at least their names. - read:users: - Read user models (excluding including servers, tokens and authentication - state). - read:users:name: Read names of users. - read:users:groups: Read users’ group membership. - read:users:activity: Read time of last user activity. - read:roles: Read role assignments. - read:roles:users: Read user role assignments. - read:roles:services: Read service role assignments. - read:roles:groups: Read group role assignments. - users:activity: Update time of last user activity. - admin:servers: Read, start, stop, create and delete user servers and their state. - admin:server_state: Read and write users’ server state. - servers: Start and stop user servers. - read:servers: - Read users’ names and their server models (excluding the server - state). - delete:servers: Stop and delete users' servers. - tokens: Read, write, create and delete user tokens. - read:tokens: Read user tokens. - admin:groups: Read and write group information, create and delete groups. - groups: - Read and write group information, including adding/removing users to/from - groups. - list:groups: List groups, including at least their names. - read:groups: Read group models. - read:groups:name: Read group names. - delete:groups: Delete groups. - list:services: List services, including at least their names. - read:services: Read service models. - read:services:name: Read service names. - read:hub: Read detailed information about the Hub. - access:servers: Access user servers via API or browser. - access:services: Access services via API or browser. - proxy: - Read information about the proxy’s routing table, sync the Hub with the - proxy and notify the Hub about a new proxy. - shutdown: Shutdown the hub. -security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope self) or have both (either can be used)? + version: 2.0.0rc3 +servers: + - url: /hub/api +security: - token: [] - oauth2: - self -basePath: /hub/api -produces: - - application/json -consumes: - - application/json paths: /: get: @@ -92,64 +21,77 @@ paths: This endpoint is not authenticated for the purpose of clients and user to identify the JupyterHub version before setting up authentication. responses: - "200": + 200: description: The JupyterHub version - schema: - type: object - properties: - version: - type: string - description: The version of JupyterHub itself + content: + application/json: + schema: + type: object + properties: + version: + type: string + description: The version of JupyterHub itself /info: get: summary: Get detailed info about JupyterHub - security: - - oauth2: - - read:hub description: | Detailed JupyterHub information, including Python version, JupyterHub's version and executable path, and which Authenticator and Spawner are active. responses: - "200": + 200: description: Detailed JupyterHub info - schema: - type: object - properties: - version: - type: string - description: The version of JupyterHub itself - python: - type: string - description: The Python version, as returned by sys.version - sys_executable: - type: string - description: The path to sys.executable running JupyterHub - authenticator: + content: + application/json: + schema: type: object properties: - class: - type: string - description: - The Python class currently active for JupyterHub - Authentication version: type: string - description: The version of the currently active Authenticator - spawner: - type: object - properties: - class: + description: The version of JupyterHub itself + python: type: string - description: - The Python class currently active for spawning single-user - notebook servers - version: + description: The Python version, as returned by sys.version + sys_executable: type: string - description: The version of the currently active Spawner - /users: + description: The path to sys.executable running JupyterHub + authenticator: + type: object + properties: + class: + type: string + description: + The Python class currently active for JupyterHub + Authentication + version: + type: string + description: The version of the currently active Authenticator + spawner: + type: object + properties: + class: + type: string + description: + The Python class currently active for spawning + single-user notebook servers + version: + type: string + description: The version of the currently active Spawner + security: + - oauth2: + - read:hub + /user: get: - summary: List users + summary: Return authenticated user's model + responses: + 200: + description: | + The authenticated user or service's model is returned + with additional information about the permissions associated with the request token. + content: + application/json: + schema: + $ref: "#/components/schemas/RequestIdentity" security: - oauth2: - read:users @@ -160,12 +102,12 @@ paths: - read:roles:users - admin:auth_state - admin:server_state + /users: + get: + summary: List users parameters: - name: state in: query - required: false - type: string - enum: ["inactive", "active", "ready"] description: | Return only users who have servers in the given state. If unspecified, return all users. @@ -175,60 +117,37 @@ paths: inactive: all users who have *no* active servers (complement of active) Added in JupyterHub 1.3 + schema: + type: string + enum: + - inactive + - active + - ready - name: offset in: query - required: false - type: number description: | Return a number users starting at the given offset. Can be used with limit to paginate. If unspecified, return all users. + schema: + type: number - name: limit in: query - required: false - type: number description: | Return a finite number of users. Can be used with offset to paginate. If unspecified, use api_page_default_limit. + schema: + type: number responses: - "200": + 200: description: The Hub's user list - schema: - type: array - items: - $ref: "#/definitions/User" - post: - summary: Create multiple users - security: - - oauth2: - - admin:users - parameters: - - name: body - in: body - required: true - schema: - type: object - properties: - usernames: + content: + application/json: + schema: type: array - description: list of usernames to create on the Hub items: - type: string - admin: - description: whether the created users should be admins - type: boolean - responses: - "201": - description: The users have been created - schema: - type: array - description: The created users - items: - $ref: "#/definitions/User" - /users/{name}: - get: - summary: Get a user by name + $ref: "#/components/schemas/User" security: - oauth2: - read:users @@ -239,610 +158,758 @@ paths: - read:roles:users - admin:auth_state - admin:server_state - parameters: - - name: name - description: username - in: path - required: true - type: string - responses: - "200": - description: The User model - schema: - $ref: "#/definitions/User" post: - summary: Create a single user + summary: Create multiple users + requestBody: + content: + application/json: + schema: + type: object + properties: + usernames: + type: array + description: list of usernames to create on the Hub + items: + type: string + admin: + type: boolean + description: whether the created users should be admins + required: true + responses: + 201: + description: The users have been created + content: + application/json: + schema: + type: array + description: The created users + items: + $ref: "#/components/schemas/User" security: - oauth2: - admin:users + x-codegen-request-body-name: body + /users/{name}: + get: + summary: Get a user by name parameters: - name: name - description: username in: path + description: username required: true - type: string - responses: - "201": - description: The user has been created schema: - $ref: "#/definitions/User" + type: string + responses: + 200: + description: The User model + content: + application/json: + schema: + $ref: "#/components/schemas/User" + security: + - oauth2: + - read:users + - read:users:name + - read:users:groups + - read:users:activity + - read:servers + - read:roles:users + - admin:auth_state + - admin:server_state + post: + summary: Create a single user + parameters: + - name: name + in: path + description: username + required: true + schema: + type: string + responses: + 201: + description: The user has been created + content: + application/json: + schema: + $ref: "#/components/schemas/User" + security: + - oauth2: + - admin:users + delete: + summary: Delete a user + parameters: + - name: name + in: path + description: username + required: true + schema: + type: string + responses: + 204: + description: The user has been deleted + content: {} + security: + - oauth2: + - admin:users patch: summary: Modify a user description: Change a user's name or admin status - security: - - oauth2: - - admin:users parameters: - name: name - description: username in: path + description: username required: true - type: string - - name: body - in: body - required: true - description: - Updated user info. At least one key to be updated (name or admin) - is required. schema: - type: object - properties: - name: - type: string - description: - the new name (optional, if another key is updated i.e. - admin) - admin: - type: boolean - description: - update admin (optional, if another key is updated i.e. - name) + type: string + requestBody: + description: + Updated user info. At least one key to be updated (name or admin) + is required. + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: + the new name (optional, if another key is updated i.e. + admin) + admin: + type: boolean + description: + update admin (optional, if another key is updated i.e. + name) + required: true responses: - "200": + 200: description: The updated user info - schema: - $ref: "#/definitions/User" - delete: - summary: Delete a user + content: + application/json: + schema: + $ref: "#/components/schemas/User" security: - oauth2: - admin:users - parameters: - - name: name - description: username - in: path - required: true - type: string - responses: - "204": - description: The user has been deleted + x-codegen-request-body-name: body /users/{name}/activity: post: summary: Notify Hub of activity for a given user. description: Notify the Hub of activity by the user, e.g. accessing a service or (more likely) actively using a server. + parameters: + - name: name + in: path + description: username + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + last_activity: + type: string + description: | + Timestamp of last-seen activity for this user. + Only needed if this is not activity associated + with using a given server. + format: date-time + servers: + type: object + properties: + : + required: + - last_activity + type: object + properties: + last_activity: + type: string + description: | + Timestamp of last-seen activity on this server. + format: date-time + description: | + Activity for a single server. + description: | + Register activity for specific servers by name. + The keys of this dict are the names of servers. + The default server has an empty name (''). + example: + last_activity: 2019-02-06T12:54:14Z + servers: + "": + last_activity: 2019-02-06T12:54:14Z + gpu: + last_activity: 2019-02-06T12:54:14Z + required: false + responses: + 401: + description: Authentication/Authorization error + content: {} + 404: + description: No such user + content: {} security: - oauth2: - users:activity - parameters: - - name: name - description: username - in: path - required: true - type: string - - name: body - in: body - schema: - type: object - properties: - last_activity: - type: string - format: date-time - description: | - Timestamp of last-seen activity for this user. - Only needed if this is not activity associated - with using a given server. - servers: - description: | - Register activity for specific servers by name. - The keys of this dict are the names of servers. - The default server has an empty name (''). - type: object - properties: - "": - description: | - Activity for a single server. - type: object - required: - - last_activity - properties: - last_activity: - type: string - format: date-time - description: | - Timestamp of last-seen activity on this server. - example: - last_activity: "2019-02-06T12:54:14Z" - servers: - "": - last_activity: "2019-02-06T12:54:14Z" - gpu: - last_activity: "2019-02-06T12:54:14Z" - responses: - "401": - $ref: "#/responses/Unauthorized" - "404": - description: No such user + x-codegen-request-body-name: body /users/{name}/server: post: summary: Start a user's single-user notebook server - security: - - oauth2: - - servers parameters: - name: name - description: username in: path + description: username required: true - type: string - - name: options - description: | - Spawn options can be passed as a JSON body - when spawning via the API instead of spawn form. - The structure of the options - will depend on the Spawner's configuration. - The body itself will be available as `user_options` for the - Spawner. - in: body - required: false schema: - type: object - + type: string + requestBody: + description: | + Spawn options can be passed as a JSON body + when spawning via the API instead of spawn form. + The structure of the options + will depend on the Spawner's configuration. + The body itself will be available as `user_options` for the + Spawner. + content: + application/json: + schema: + type: object + required: false responses: - "201": + 201: description: The user's notebook server has started - "202": + content: {} + 202: description: The user's notebook server has not yet started, but has been requested - delete: - summary: Stop a user's server + content: {} security: - oauth2: - servers + x-codegen-request-body-name: options + delete: + summary: Stop a user's server parameters: - name: name - description: username in: path + description: username required: true - type: string + schema: + type: string responses: - "204": - description: The user's notebook server has stopped - "202": + 202: description: The user's notebook server has not yet stopped as it is taking a while to stop - /users/{name}/servers/{server_name}: - post: - summary: Start a user's single-user named-server notebook server + content: {} + 204: + description: The user's notebook server has stopped + content: {} security: - oauth2: - servers + /users/{name}/servers/{server_name}: + post: + summary: Start a user's single-user named-server notebook server parameters: - name: name - description: username in: path + description: username required: true - type: string + schema: + type: string - name: server_name + in: path description: | name given to a named-server. Note that depending on your JupyterHub infrastructure there are chracterter size limitation to `server_name`. Default spawner with K8s pod will not allow Jupyter Notebooks to be spawned with a name that contains more than 253 characters (keep in mind that the pod will be spawned with extra characters to identify the user and hub). - in: path required: true - type: string - - name: options - description: | - Spawn options can be passed as a JSON body - when spawning via the API instead of spawn form. - The structure of the options - will depend on the Spawner's configuration. - in: body - required: false schema: - type: object + type: string + requestBody: + description: | + Spawn options can be passed as a JSON body + when spawning via the API instead of spawn form. + The structure of the options + will depend on the Spawner's configuration. + content: + application/json: + schema: + type: object + required: false responses: - "201": + 201: description: The user's notebook named-server has started - "202": + content: {} + 202: description: The user's notebook named-server has not yet started, but has been requested - delete: - summary: Stop a user's named-server + content: {} security: - oauth2: - servers + x-codegen-request-body-name: options + delete: + summary: Stop a user's named server + description: | + To remove the named server in addition to deleting it, + the body may be a JSON dictionary with a boolean `remove` field: + + ```json + {"remove": true} + ``` parameters: - name: name + in: path description: username - in: path required: true - type: string - - name: server_name - description: name given to a named-server - in: path - required: true - type: string - - name: body - in: body - required: false schema: - type: object - properties: - remove: - type: boolean - description: | - Whether to fully remove the server, rather than just stop it. - Removing a server deletes things like the state of the stopped server. - Default: false. + type: string + - name: server_name + in: path + description: name given to a named-server + required: true + schema: + type: string + + # FIXME: openapi 3.1 is required for requestBody on DELETE + # we probably shouldn't have request bodies on DELETE + # requestBody: + # content: + # application/json: + # schema: + # type: object + # properties: + # remove: + # type: boolean + # description: | + # Whether to fully remove the server, rather than just stop it. + # Removing a server deletes things like the state of the stopped server. + # Default: false. + # required: false responses: - "204": - description: The user's notebook named-server has stopped - "202": + 202: description: The user's notebook named-server has not yet stopped as it is taking a while to stop + content: {} + 204: + description: The user's notebook named-server has stopped + content: {} + security: + - oauth2: + - servers + # x-codegen-request-body-name: body /users/{name}/tokens: - parameters: - - name: name - description: username - in: path - required: true - type: string get: summary: List tokens for the user - security: - - oauth2: - - read:tokens - responses: - "200": - description: The list of tokens - schema: - type: array - items: - $ref: "#/definitions/Token" - "401": - $ref: "#/responses/Unauthorized" - "404": - description: No such user - post: - summary: Create a new token for the user - security: - - oauth2: - - tokens parameters: - - name: token_params - in: body - required: false + - name: name + in: path + description: username + required: true schema: - type: object - properties: - expires_in: - type: number - description: - lifetime (in seconds) after which the requested token will - expire. - note: - type: string - description: A note attached to the token for future bookkeeping - roles: + type: string + responses: + 200: + description: The list of tokens + content: + application/json: + schema: type: array items: - type: string - description: A list of role names that the token should have - responses: - "201": - description: The newly created token - schema: - $ref: "#/definitions/Token" - "400": - description: Body must be a JSON dict or empty - "403": - description: Requested role does not exist - /users/{name}/tokens/{token_id}: - parameters: - - name: name - description: username - in: path - required: true - type: string - - name: token_id - in: path - required: true - type: string - get: - summary: Get the model for a token by id + $ref: "#/components/schemas/Token" + 401: + description: Authentication/Authorization error + content: {} + 404: + description: No such user + content: {} security: - oauth2: - read:tokens - responses: - "200": - description: The info for the new token + post: + summary: Create a new token for the user + parameters: + - name: name + in: path + description: username + required: true schema: - $ref: "#/definitions/Token" - delete: - summary: Delete (revoke) a token by id + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + expires_in: + type: number + description: + lifetime (in seconds) after which the requested token + will expire. + note: + type: string + description: A note attached to the token for future bookkeeping + roles: + type: array + description: A list of role names that the token should have + items: + type: string + required: false + responses: + 201: + description: The newly created token + content: + application/json: + schema: + $ref: "#/components/schemas/Token" + 400: + description: Body must be a JSON dict or empty + content: {} + 403: + description: Requested role does not exist + content: {} security: - oauth2: - tokens - responses: - "204": - description: The token has been deleted - /user: + x-codegen-request-body-name: token_params + /users/{name}/tokens/{token_id}: get: - summary: Return authenticated user's model + summary: Get the model for a token by id + parameters: + - name: name + in: path + description: username + required: true + schema: + type: string + - name: token_id + in: path + required: true + schema: + type: string + responses: + 200: + description: The info for the new token + content: + application/json: + schema: + $ref: "#/components/schemas/Token" security: - oauth2: - - read:users - - read:users:name - - read:users:groups - - read:users:activity - - read:servers - - read:roles:users - - admin:auth_state - - admin:server_state - responses: - "200": - description: The authenticated user's model is returned. + - read:tokens + delete: + summary: Delete (revoke) a token by id + parameters: + - name: name + in: path + description: username + required: true schema: - $ref: "#/definitions/User" + type: string + - name: token_id + in: path + required: true + schema: + type: string + responses: + 204: + description: The token has been deleted + content: {} + security: + - oauth2: + - tokens /groups: get: summary: List groups - security: - - oauth2: - - read:groups - - read:groups:name - - read:roles:groups parameters: - name: offset in: query - required: false - type: number description: | Return a number of groups starting at the specified offset. Can be used with limit to paginate. If unspecified, return all groups. + schema: + type: number - name: limit in: query - required: false - type: number description: | Return a finite number of groups. Can be used with offset to paginate. If unspecified, use api_page_default_limit. - responses: - "200": - description: The list of groups schema: - type: array - items: - $ref: "#/definitions/Group" - /groups/{name}: - get: - summary: Get a group by name + type: number + responses: + 200: + description: The list of groups + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Group" security: - oauth2: - read:groups - read:groups:name - read:roles:groups + /groups/{name}: + get: + summary: Get a group by name parameters: - name: name - description: group name in: path + description: group name required: true - type: string - responses: - "200": - description: The group model schema: - $ref: "#/definitions/Group" + type: string + responses: + 200: + description: The group model + content: + application/json: + schema: + $ref: "#/components/schemas/Group" + security: + - oauth2: + - read:groups + - read:groups:name + - read:roles:groups post: summary: Create a group + parameters: + - name: name + in: path + description: group name + required: true + schema: + type: string + responses: + 201: + description: The group has been created + content: + application/json: + schema: + $ref: "#/components/schemas/Group" security: - oauth2: - admin:groups - parameters: - - name: name - description: group name - in: path - required: true - type: string - responses: - "201": - description: The group has been created - schema: - $ref: "#/definitions/Group" delete: summary: Delete a group + parameters: + - name: name + in: path + description: group name + required: true + schema: + type: string + responses: + 204: + description: The group has been deleted + content: {} security: - oauth2: - admin:groups - parameters: - - name: name - description: group name - in: path - required: true - type: string - responses: - "204": - description: The group has been deleted /groups/{name}/users: post: summary: Add users to a group - security: - - oauth2: - - groups parameters: - name: name - description: group name in: path + description: group name required: true - type: string - - name: body - in: body - required: true - description: The users to add to the group schema: - type: object - properties: - users: - type: array - description: List of usernames to add to the group - items: - type: string + type: string + requestBody: + description: The users to add to the group + content: + application/json: + schema: + type: object + properties: + users: + type: array + description: List of usernames to add to the group + items: + type: string + required: true responses: - "200": + 200: description: The users have been added to the group - schema: - $ref: "#/definitions/Group" - delete: - summary: Remove users from a group + content: + application/json: + schema: + $ref: "#/components/schemas/Group" security: - oauth2: - groups + x-codegen-request-body-name: body + delete: + summary: | + Remove users from a group + description: | + Body should be a JSON dictionary + where `users` is a list of usernames to remove from the groups. + + ```json + { + "users": ["name1", "name2"] + } + ``` + parameters: - name: name - description: group name in: path + description: group name required: true - type: string - - name: body - in: body - required: true - description: The users to remove from the group schema: - type: object - properties: - users: - type: array - description: List of usernames to remove from the group - items: - type: string + type: string + # requestBody: + # description: The users to remove from the group + # content: + # application/json: + # schema: + # type: object + # properties: + # users: + # type: array + # description: List of usernames to remove from the group + # items: + # type: string + # required: true responses: - "200": + 200: description: The users have been removed from the group + content: {} + security: + - oauth2: + - groups + x-codegen-request-body-name: body /services: get: summary: List services + responses: + 200: + description: The service list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Service" security: - oauth2: - read:services - read:services:name - read:roles:services - responses: - "200": - description: The service list - schema: - type: array - items: - $ref: "#/definitions/Service" /services/{name}: get: summary: Get a service by name + parameters: + - name: name + in: path + description: service name + required: true + schema: + type: string + responses: + 200: + description: The Service model + content: + application/json: + schema: + $ref: "#/components/schemas/Service" security: - oauth2: - read:services - read:services:name - read:roles:services - parameters: - - name: name - description: service name - in: path - required: true - type: string - responses: - "200": - description: The Service model - schema: - $ref: "#/definitions/Service" /proxy: get: summary: Get the proxy's routing table description: A convenience alias for getting the routing table directly from the proxy - security: - - oauth2: - - proxy parameters: - name: offset in: query - required: false - type: number description: | Return a number of routes starting at the given offset. Can be used with limit to paginate. If unspecified, return all routes. + schema: + type: number - name: limit in: query - required: false - type: number description: | Return a finite number of routes. Can be used with offset to paginate. If unspecified, use api_page_default_limit - responses: - "200": - description: Routing table schema: - type: object - description: - configurable-http-proxy routing table (see configurable-http-proxy - docs for details) - post: - summary: Force the Hub to sync with the proxy + type: number + responses: + 200: + description: Routing table + content: + application/json: + schema: + type: object + description: + configurable-http-proxy routing table (see configurable-http-proxy + docs for details) security: - oauth2: - proxy + post: + summary: Force the Hub to sync with the proxy responses: - "200": + 200: description: Success + content: {} + security: + - oauth2: + - proxy patch: summary: Notify the Hub about a new proxy description: Notifies the Hub of a new proxy to use. + requestBody: + description: + Any values that have changed for the new proxy. All keys are + optional. + content: + application/json: + schema: + type: object + properties: + ip: + type: string + description: IP address of the new proxy + port: + type: string + description: Port of the new proxy + protocol: + type: string + description: Protocol of new proxy, if changed + auth_token: + type: string + description: CONFIGPROXY_AUTH_TOKEN for the new proxy + required: true + responses: + 200: + description: Success + content: {} security: - oauth2: - proxy - parameters: - - name: body - in: body - required: true - description: - Any values that have changed for the new proxy. All keys are - optional. - schema: - type: object - properties: - ip: - type: string - description: IP address of the new proxy - port: - type: string - description: Port of the new proxy - protocol: - type: string - description: Protocol of new proxy, if changed - auth_token: - type: string - description: CONFIGPROXY_AUTH_TOKEN for the new proxy - responses: - "200": - description: Success + x-codegen-request-body-name: body /authorizations/token: post: summary: Request a new API token @@ -852,46 +919,54 @@ paths: in the JSON request body. Logging in via this method is only available when the active Authenticator accepts passwords (e.g. not OAuth). + requestBody: + content: + application/json: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: false + responses: + 200: + description: The new API token + content: + application/json: + schema: + type: object + properties: + token: + type: string + description: The new API token. + 403: + description: The user can not be authenticated. + content: {} security: - oauth2: - tokens - parameters: - - name: credentials - in: body - schema: - type: object - properties: - username: - type: string - password: - type: string - responses: - "200": - description: The new API token - schema: - type: object - properties: - token: - type: string - description: The new API token. - "403": - description: The user can not be authenticated. + x-codegen-request-body-name: credentials /authorizations/token/{token}: get: summary: Identify a user or service from an API token - security: - - oauth2: - - (no_scope) parameters: - name: token in: path required: true - type: string + schema: + type: string responses: - "200": + 200: description: The user or service identified by the API token - "404": + content: {} + 404: description: A user or service is not found. + content: {} + security: + - oauth2: + - (no_scope) /authorizations/cookie/{cookie_name}/{cookie_value}: get: summary: Identify a user from a cookie @@ -902,306 +977,445 @@ paths: - name: cookie_name in: path required: true - type: string + schema: + type: string - name: cookie_value in: path required: true - type: string - responses: - "200": - description: The user identified by the cookie schema: - $ref: "#/definitions/User" - "404": + type: string + responses: + 200: + description: The user identified by the cookie + content: + application/json: + schema: + $ref: "#/components/schemas/User" + 404: description: A user is not found. - deprecated: true # minrk: let’s not add a scope for this, let’s remove it + content: {} + deprecated: true /oauth2/authorize: get: - summary: "OAuth 2.0 authorize endpoint" + summary: OAuth 2.0 authorize endpoint description: | Redirect users to this URL to begin the OAuth process. It is not an API endpoint. parameters: - name: client_id + in: query description: The client id - in: query required: true - type: string + schema: + type: string - name: response_type + in: query description: The response type (always 'code') - in: query required: true - type: string + schema: + type: string - name: state + in: query description: A state string - in: query - required: false - type: string + schema: + type: string - name: redirect_uri - description: The redirect url in: query + description: The redirect url required: true - type: string + schema: + type: string responses: - "200": + 200: description: Success - "400": + content: {} + 400: description: OAuth2Error + content: {} /oauth2/token: post: summary: Request an OAuth2 token description: | Request an OAuth2 token from an authorization code. This request completes the OAuth process. - consumes: - - application/x-www-form-urlencoded - parameters: - - name: client_id - description: The client id - in: formData - required: true - type: string - - name: client_secret - description: The client secret - in: formData - required: true - type: string - - name: grant_type - description: The grant type (always 'authorization_code') - in: formData - required: true - type: string - - name: code - description: The code provided by the authorization redirect - in: formData - required: true - type: string - - name: redirect_uri - description: The redirect url - in: formData - required: true - type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + required: + - client_id + - client_secret + - code + - grant_type + - redirect_uri + properties: + client_id: + type: string + description: The client id + client_secret: + type: string + description: The client secret + grant_type: + type: string + description: The grant type (always 'authorization_code') + code: + type: string + description: The code provided by the authorization redirect + redirect_uri: + type: string + description: The redirect url + required: true responses: - "200": + 200: description: JSON response including the token - schema: - type: object - properties: - access_token: - type: string - description: The new API token for the user - token_type: - type: string - description: Will always be 'Bearer' + content: + application/json: + schema: + type: object + properties: + access_token: + type: string + description: The new API token for the user + token_type: + type: string + description: Will always be 'Bearer' /shutdown: post: summary: Shutdown the Hub + requestBody: + content: + application/json: + schema: + type: object + properties: + proxy: + type: boolean + description: + Whether the proxy should be shutdown as well (default + from Hub config) + servers: + type: boolean + description: + Whether users' notebook servers should be shutdown + as well (default from Hub config) + required: false + responses: + 202: + description: Shutdown successful + content: {} + 400: + description: Unexpeced value for proxy or servers + content: {} security: - oauth2: - shutdown - parameters: - - name: body - in: body - schema: - type: object - properties: - proxy: - type: boolean - description: - Whether the proxy should be shutdown as well (default from - Hub config) - servers: - type: boolean - description: - Whether users' notebook servers should be shutdown as well - (default from Hub config) - responses: - "202": - description: Shutdown successful - "400": - description: Unexpeced value for proxy or servers -# Descriptions of common responses -responses: - NotFound: - description: The specified resource was not found - Unauthorized: - description: Authentication/Authorization error -definitions: - User: - type: object - properties: - name: - type: string - description: The user's name - admin: - type: boolean - description: Whether the user is an admin - roles: - type: array - description: The names of roles this user has - items: + x-codegen-request-body-name: body +components: + schemas: + User: + type: object + properties: + name: type: string - groups: - type: array - description: The names of groups where this user is a member - items: + description: The user's name + admin: + type: boolean + description: Whether the user is an admin + roles: + type: array + description: The names of roles this user has + items: + type: string + groups: + type: array + description: The names of groups where this user is a member + items: + type: string + server: type: string - server: - type: string - description: The user's notebook server's base URL, if running; null if not. - pending: - type: string - enum: ["spawn", "stop", null] - description: The currently pending action, if any - last_activity: - type: string - format: date-time - description: Timestamp of last-seen activity from the user - servers: - type: array - description: The active servers for this user. - items: - $ref: "#/definitions/Server" - auth_state: - type: string - #TODO: will there be predefined states? Should it rather be object instead of string? - description: - Authentication state of the user. Only available with admin:users:auth_state - scope. None otherwise. - Server: - type: object - properties: - name: - type: string - description: - The server's name. The user's default server has an empty name - ('') - ready: - type: boolean - description: | - Whether the server is ready for traffic. - Will always be false when any transition is pending. - pending: - type: string - enum: ["spawn", "stop", null] - description: | - The currently pending action, if any. - A server is not ready if an action is pending. - url: - type: string - description: | - The URL where the server can be accessed - (typically /user/:name/:server.name/). - progress_url: - type: string - description: | - The URL for an event-stream to retrieve events during a spawn. - started: - type: string - format: date-time - description: UTC timestamp when the server was last started. - last_activity: - type: string - format: date-time - description: UTC timestamp last-seen activity on this server. - state: - type: object - description: - Arbitrary internal state from this server's spawner. Only available - on the hub's users list or get-user-by-name method, and only with admin:users:server_state - scope. None otherwise. - user_options: - type: object - description: - User specified options for the user's spawned instance of a single-user - server. - Group: - type: object - properties: - name: - type: string - description: The group's name - users: - type: array - description: The names of users who are members of this group - items: + description: + The user's notebook server's base URL, if running; null if + not. + pending: type: string - roles: - type: array - description: The names of roles this group has - items: + description: The currently pending action, if any + enum: + - spawn + - stop + last_activity: type: string - Service: - type: object - properties: - name: - type: string - description: The service's name - admin: - type: boolean - description: Whether the service is an admin - roles: - type: array - description: The names of roles this service has - items: + description: Timestamp of last-seen activity from the user + format: date-time + servers: + type: array + description: The active servers for this user. + items: + $ref: "#/components/schemas/Server" + auth_state: + type: object + properties: {} + description: | + Authentication state of the user. Only available with admin:users:auth_state + scope. None otherwise. + Server: + type: object + properties: + name: type: string - url: - type: string - description: The internal url where the service is running - prefix: - type: string - description: The proxied URL prefix to the service's url - pid: - type: number - description: The PID of the service process (if managed) - command: - type: array - description: The command used to start the service (if managed) - items: + description: + The server's name. The user's default server has an empty name + ('') + ready: + type: boolean + description: | + Whether the server is ready for traffic. + Will always be false when any transition is pending. + pending: type: string - info: - type: object - description: | - Additional information a deployment can attach to a service. - JupyterHub does not use this field. - Token: - type: object - properties: - token: - type: string - description: - The token itself. Only present in responses to requests for a - new token. - id: - type: string - description: The id of the API token. Used for modifying or deleting the token. - user: - type: string - description: The user that owns a token (undefined if owned by a service) - service: - type: string - description: The service that owns the token (undefined of owned by a user) - roles: - type: array - description: The names of roles this token has - items: + description: | + The currently pending action, if any. + A server is not ready if an action is pending. + enum: + - spawn + - stop + url: type: string - note: - type: string - description: - A note about the token, typically describing what it was created - for. - created: - type: string - format: date-time - description: Timestamp when this token was created - expires_at: - type: string - format: date-time - description: Timestamp when this token expires. Null if there is no expiry. - last_activity: - type: string - format: date-time - description: | - Timestamp of last-seen activity using this token. - Can be null if token has never been used. + description: | + The URL where the server can be accessed + (typically /user/:name/:server.name/). + progress_url: + type: string + description: | + The URL for an event-stream to retrieve events during a spawn. + started: + type: string + description: UTC timestamp when the server was last started. + format: date-time + last_activity: + type: string + description: UTC timestamp last-seen activity on this server. + format: date-time + state: + type: object + properties: {} + description: + Arbitrary internal state from this server's spawner. Only available + on the hub's users list or get-user-by-name method, and only with admin:users:server_state + scope. None otherwise. + user_options: + type: object + properties: {} + description: + User specified options for the user's spawned instance of a + single-user server. + RequestIdentity: + description: | + The model for the entity making the request. + Extends User or Service model to add information about the specific credentials (e.g. session or token-authorised scopes). + allOf: + - type: object + oneOf: + - $ref: "#/components/schemas/User" + - $ref: "#/components/schemas/Service" + discriminator: + propertyName: kind + mapping: + user: "#/components/schemas/User" + service: "#/components/schemas/Service" + - type: object + properties: + session_id: + type: string + nullable: true + description: | + The session id associated with the request's OAuth token, if any. + null, if the request token not associated with a session id. + + Added in 2.0. + scopes: + type: array + description: | + The list of all expanded scopes the request credentials have access to. + + Added in 2.0. + items: + type: string + example: + - "read:users" + - "access:servers!user=name" + Group: + type: object + properties: + name: + type: string + description: The group's name + users: + type: array + description: The names of users who are members of this group + items: + type: string + roles: + type: array + description: The names of roles this group has + items: + type: string + Service: + type: object + properties: + name: + type: string + description: The service's name + admin: + type: boolean + description: Whether the service is an admin + roles: + type: array + description: The names of roles this service has + items: + type: string + url: + type: string + description: The internal url where the service is running + prefix: + type: string + description: The proxied URL prefix to the service's url + pid: + type: number + description: The PID of the service process (if managed) + command: + type: array + description: The command used to start the service (if managed) + items: + type: string + info: + type: object + properties: {} + description: | + Additional information a deployment can attach to a service. + JupyterHub does not use this field. + Token: + type: object + properties: + token: + type: string + description: + The token itself. Only present in responses to requests for + a new token. + id: + type: string + description: + The id of the API token. Used for modifying or deleting the + token. + user: + type: string + description: The user that owns a token (undefined if owned by a service) + service: + type: string + description: The service that owns the token (undefined of owned by a user) + roles: + type: array + description: The names of roles this token has + items: + type: string + note: + type: string + description: + A note about the token, typically describing what it was created + for. + created: + type: string + description: Timestamp when this token was created + format: date-time + expires_at: + type: string + description: Timestamp when this token expires. Null if there is no expiry. + format: date-time + last_activity: + type: string + description: | + Timestamp of last-seen activity using this token. + Can be null if token has never been used. + format: date-time + session_id: + type: string + nullable: true + description: | + The session id associated with the token, if any. + Only used for tokens set during oauth flows. + + Added in 2.0. + responses: + NotFound: + description: The specified resource was not found + content: {} + Unauthorized: + description: Authentication/Authorization error + content: {} + securitySchemes: + token: + type: apiKey + name: Authorization + in: header + oauth2: + type: oauth2 + flows: + authorizationCode: + authorizationUrl: https://hub.example/hub/api/oauth2/authorize + tokenUrl: https://hub.example/hub/api/oauth2/token + scopes: + (no_scope): Identify the owner of the requesting entity. + self: + The user’s own resources _(metascope for users, resolves to (no_scope) + for services)_ + inherit: + Everything that the token-owning entity can access _(metascope + for tokens)_ + admin:users: + Read, write, create and delete users and their authentication + state, not including their servers or tokens. + admin:auth_state: Read a user’s authentication state. + users: + Read and write permissions to user models (excluding servers, tokens + and authentication state). + delete:users: Delete users. + list:users: List users, including at least their names. + read:users: + Read user models (excluding including servers, tokens and + authentication state). + read:users:name: Read names of users. + read:users:groups: Read users’ group membership. + read:users:activity: Read time of last user activity. + read:roles: Read role assignments. + read:roles:users: Read user role assignments. + read:roles:services: Read service role assignments. + read:roles:groups: Read group role assignments. + users:activity: Update time of last user activity. + admin:servers: + Read, start, stop, create and delete user servers and their + state. + admin:server_state: Read and write users’ server state. + servers: Start and stop user servers. + read:servers: + Read users’ names and their server models (excluding the + server state). + delete:servers: Stop and delete users' servers. + tokens: Read, write, create and delete user tokens. + read:tokens: Read user tokens. + admin:groups: Read and write group information, create and delete groups. + groups: + Read and write group information, including adding/removing users + to/from groups. + list:groups: List groups, including at least their names. + read:groups: Read group models. + read:groups:name: Read group names. + delete:groups: Delete groups. + list:services: List services, including at least their names. + read:services: Read service models. + read:services:name: Read service names. + read:hub: Read detailed information about the Hub. + access:servers: Access user servers via API or browser. + access:services: Access services via API or browser. + proxy: + Read information about the proxy’s routing table, sync the Hub + with the proxy and notify the Hub about a new proxy. + shutdown: Shutdown the hub. diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index ed7241a7..a757aa02 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -114,7 +114,9 @@ class ScopeTableGenerator: if doc_description: description = doc_description scope_dict[scope] = description - content['securityDefinitions']['oauth2']['scopes'] = scope_dict + content['components']['securitySchemes']['oauth2']['flows'][ + 'authorizationCode' + ]['scopes'] = scope_dict with open(filename, 'w') as f: yaml.dump(content, f) diff --git a/docs/source/reference/rest-api.md b/docs/source/reference/rest-api.md index 38d690f1..117d7e10 100644 --- a/docs/source/reference/rest-api.md +++ b/docs/source/reference/rest-api.md @@ -5,7 +5,7 @@ Below is an interactive view of JupyterHub's OpenAPI specification. - + diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 612a76c9..8994b659 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -213,6 +213,7 @@ class APIHandler(BaseHandler): 'last_activity': isoformat(token.last_activity), 'expires_at': isoformat(token.expires_at), 'note': token.note, + 'session_id': token.session_id, 'oauth_client': token.oauth_client.description or token.oauth_client.identifier, } diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 2b977277..2d0bfeff 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -58,6 +58,14 @@ class SelfAPIHandler(APIHandler): model = get_model(user) + # add session_id associated with token + # added in 2.0 + token = self.get_token() + if token: + model["session_id"] = token.session_id + else: + model["session_id"] = None + # add scopes to identify model, # but not the scopes we added to ensure we could read our own model model["scopes"] = sorted(self.expanded_scopes.difference(_added_scopes)) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index aef2324b..3c1ccc2f 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -346,6 +346,7 @@ class BaseHandler(RequestHandler): auth_info['auth_state'] = await user.get_auth_state() return await self.auth_to_user(auth_info, user) + @functools.lru_cache() def get_token(self): """get token from authorization header""" token = self.get_auth_token()