Update http authentication docs with new operation level auth and scopes (#2960)

PR added support for it but we need to update the docs to explain the
new feature.

---------

Co-authored-by: Brian Terlson <brian.terlson@microsoft.com>
This commit is contained in:
Timothee Guerin 2024-02-28 11:40:28 -08:00 коммит произвёл GitHub
Родитель 628517e0c2
Коммит 8b062e33bb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
8 изменённых файлов: 110 добавлений и 29 удалений

Просмотреть файл

@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/http"
- "@typespec/openapi3"
---

Просмотреть файл

@ -70,6 +70,7 @@ words:
- protoc
- pwsh
- regen
- respecify
- rpaas
- rushx
- safeint

Просмотреть файл

@ -4,40 +4,40 @@ title: Authentication
# Configure Http Authentication
Notes:
- Authentication right now can ONLY be configured at the service level.
## Configure
Authentication can be configured using the `@useAuth` decorator on the service namespace. The decorator accept a few options:
Authentication can be configured using the `@useAuth` decorator on a service namespace, sub-namespace, interface or operation.
- A security scheme (see options [here](https://github.com/microsoft/typespec/blob/main/packages/http/lib/auth.tsp)). This means this is the security scheme to use to authenticate this service.
The `@useAuth` decorator takes as input the security to apply for all operations contained in the type. If another `@useAuth` was specified on a parent type the new one will override the value of the parent. [See application hierarchy](#application-hierarchy)
```typespec
@useAuth(Auth1)
```
The input can be a:
- A tuple of security scheme. This means ALL the different security schemes of the tuple MUST be used together to authenticate this service.
- A single security scheme (see options [here](https://github.com/microsoft/typespec/blob/main/packages/http/lib/auth.tsp)).
```typespec
// Use BOTH Auth1 or Auth2
@useAuth([Auth1, Auth2])
```
```typespec
@useAuth(Auth1)
```
- A union of security scheme. This means EITHER of the security schemes can be used to authenticate this service
- A tuple of security schemes. This creates a security group and means **all** the security schemes in the group **must** be used together to authenticate this service.
```typespec
// Use EITHER Auth1 or Auth2
@useAuth(Auth1 | Auth2)
```
```typespec
// Use BOTH Auth1 or Auth2
@useAuth([Auth1, Auth2])
```
- A union of tuple security scheme. This means EITHER of the security groups schemes can be used to authenticate this service
- A union of security schemes. This means **one** of the security schemes **must** be used to authenticate this service.
```typespec
// Use EITHER (Auth1 AND Auth2) OR Auth3
@useAuth([Auth1, Auth2] | Auth3)
```
```typespec
// Use EITHER Auth1 or Auth2
@useAuth(Auth1 | Auth2)
```
- A union of security schemes and tuples representing security groups. This means **one** of the security groups or security schemes **must** be used to authenticate this service.
```typespec
// Use EITHER (Auth1 AND Auth2) OR Auth3
@useAuth([Auth1, Auth2] | Auth3)
```
## Available security schemes
@ -111,3 +111,75 @@ OAuth 2.0 is an authorization protocol that gives an API client limited access t
OAuth relies on authentication scenarios called flows, which allow the resource owner (user) to share the protected content from the resource server without sharing their credentials.
For that purpose, an OAuth 2.0 server issues access tokens that the client applications can use to access protected resources on behalf of the resource owner.
For more information about OAuth 2.0, see oauth.net and RFC 6749.
## Application hierarchy
The `@useAuth` decorator can be used on a service namespace, sub-namespace, interface or operation. The security scheme specified will be applied to all operations contained in the type.
A child type with a `@useAuth` will **override** the security scheme of the parent type. If the goal is to append a new scheme, you must re-specify the security schemes on the parent and add the new scheme.
### Examples
All operations of `MyService` will use `BasicAuth` to authenticate
```typespec
@useAuth(BasicAuth)
namespace MyService;
op one(): void;
op two(): void;
```
`one` will use `ApiKey` auth and `two` will use the `Basic` auth.
```typespec
@useAuth(BasicAuth)
namespace MyService;
@useAuth(ApiKeyAuth<ApiKeyLocation.query, "api_key">)
op one(): void; // Use ApiKey only
op two(): void; // Use BasicAuth
```
`one` will use `ApiKey` or `Basic` auth and `two` will use the `Basic` auth.
```typespec
@useAuth(BasicAuth)
namespace MyService;
@useAuth(BasicAuth | ApiKeyAuth<ApiKeyLocation.query, "api_key">)
op one(): void; // Use ApiKey only
op two(): void; // Use BasicAuth
```
## OAuth2 Scopes
The `OAuth2` security scheme can have a list of scopes that must be granted to the OAuth2 token to be able to use the operations the security scheme applies to.
When different operations have different scopes, you will likely want to create a template that allows providing OAuth scopes without having to respecify the other properties of the security scheme:
```tsp
alias MyOAuth2<Scopes extends valueof string[]> = OAuth2Auth<[{
type: OAuth2FlowType.implicit;
authorizationUrl: "https://api.example.com/oauth2/authorize";
refreshUrl: "https://api.example.com/oauth2/refresh";
}], Scopes>;
@useAuth<MyOAuth2<["read"]>>
namespace DemoService;
// Use OAuth2 with the "read" scope
op list(): string[];
// Use OAuth2 with the "read" scope or no authentication at all
@useAuth<MyOAuth2<["read"]> | NoAuth>
op read(): string;
// Use OAuth2 with the "write" scope
@useAuth(MyAuth<["write"]>)
op write(value: string): void;
// Use OAuth2 with the "delete" scope
@useAuth(MyAuth<["delete"]>)
op delete(value: string): void;
```

Просмотреть файл

@ -111,7 +111,7 @@ model ApiKeyAuth<Location extends ApiKeyLocation, Name extends string> {
* @template Scopes The list of OAuth2 scopes, which are common for every flow from `Flows`. This list is combined with the scopes defined in specific OAuth2 flows.
*/
@doc("")
model OAuth2Auth<Flows extends OAuth2Flow[], Scopes extends string[] = []> {
model OAuth2Auth<Flows extends OAuth2Flow[], Scopes extends valueof string[] = []> {
@doc("OAuth2 authentication")
type: AuthType.oauth2;

Просмотреть файл

@ -18,7 +18,7 @@ export type HttpVerb = "get" | "put" | "post" | "patch" | "delete" | "head";
/** @deprecated use Authentication */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type ServiceAuthentication = Authentication;
export type ServiceAuthentication = Authentication;
export interface Authentication {
/**

Просмотреть файл

@ -780,7 +780,7 @@ describe("http: decorators", () => {
it("can specify OAuth2 with scopes, which are default for every flow", async () => {
const { Foo } = (await runner.compile(`
alias MyAuth<T extends string[]> = OAuth2Auth<Flows=[{
alias MyAuth<T extends valueof string[]> = OAuth2Auth<Flows=[{
type: OAuth2FlowType.implicit;
authorizationUrl: "https://api.example.com/oauth2/authorize";
refreshUrl: "https://api.example.com/oauth2/refresh";

Просмотреть файл

@ -258,7 +258,7 @@ describe("openapi3: security", () => {
`
namespace Test;
alias MyOauth<T extends string[]> = OAuth2Auth<Flows=[{
alias MyOauth<T extends valueof string[]> = OAuth2Auth<Flows=[{
type: OAuth2FlowType.implicit;
authorizationUrl: "https://api.example.com/oauth2/authorize";
refreshUrl: "https://api.example.com/oauth2/refresh";

Просмотреть файл

@ -8,7 +8,7 @@ using TypeSpec.Http;
@useAuth(BearerAuth | MyAuth<["read", "write"]>)
namespace TypeSpec.OperationAuth;
alias MyAuth<Scopes extends string[]> = OAuth2Auth<
alias MyAuth<Scopes extends valueof string[]> = OAuth2Auth<
Flows = [
{
type: OAuth2FlowType.implicit;