From 8b062e33bbc4273d2470fa9fbc182df8ce1ef0b7 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 28 Feb 2024 11:40:28 -0800 Subject: [PATCH] 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 --- ...docs-operation-level-2024-1-27-19-50-39.md | 8 ++ cspell.yaml | 1 + docs/libraries/http/authentication.md | 120 ++++++++++++++---- packages/http/lib/auth.tsp | 2 +- packages/http/src/types.ts | 2 +- packages/http/test/http-decorators.test.ts | 2 +- packages/openapi3/test/security.test.ts | 2 +- .../specs/authentication/operation-auth.tsp | 2 +- 8 files changed, 110 insertions(+), 29 deletions(-) create mode 100644 .chronus/changes/docs-operation-level-2024-1-27-19-50-39.md diff --git a/.chronus/changes/docs-operation-level-2024-1-27-19-50-39.md b/.chronus/changes/docs-operation-level-2024-1-27-19-50-39.md new file mode 100644 index 000000000..1d4a034c6 --- /dev/null +++ b/.chronus/changes/docs-operation-level-2024-1-27-19-50-39.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: internal +packages: + - "@typespec/http" + - "@typespec/openapi3" +--- + diff --git a/cspell.yaml b/cspell.yaml index 96e8aef6c..c3c84fa5c 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -70,6 +70,7 @@ words: - protoc - pwsh - regen + - respecify - rpaas - rushx - safeint diff --git a/docs/libraries/http/authentication.md b/docs/libraries/http/authentication.md index 70390f556..b21632364 100644 --- a/docs/libraries/http/authentication.md +++ b/docs/libraries/http/authentication.md @@ -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) +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) +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 = OAuth2Auth<[{ + type: OAuth2FlowType.implicit; + authorizationUrl: "https://api.example.com/oauth2/authorize"; + refreshUrl: "https://api.example.com/oauth2/refresh"; +}], Scopes>; + +@useAuth> +namespace DemoService; + + +// Use OAuth2 with the "read" scope +op list(): string[]; + +// Use OAuth2 with the "read" scope or no authentication at all +@useAuth | 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; + +``` diff --git a/packages/http/lib/auth.tsp b/packages/http/lib/auth.tsp index 1cf81dd2a..ec4a39ba4 100644 --- a/packages/http/lib/auth.tsp +++ b/packages/http/lib/auth.tsp @@ -111,7 +111,7 @@ model ApiKeyAuth { * @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 { +model OAuth2Auth { @doc("OAuth2 authentication") type: AuthType.oauth2; diff --git a/packages/http/src/types.ts b/packages/http/src/types.ts index 0b9e039b4..7daf41f88 100644 --- a/packages/http/src/types.ts +++ b/packages/http/src/types.ts @@ -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 { /** diff --git a/packages/http/test/http-decorators.test.ts b/packages/http/test/http-decorators.test.ts index 85271879f..ac3a002c7 100644 --- a/packages/http/test/http-decorators.test.ts +++ b/packages/http/test/http-decorators.test.ts @@ -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 = OAuth2Auth = OAuth2Auth { ` namespace Test; - alias MyOauth = OAuth2Auth = OAuth2Auth) namespace TypeSpec.OperationAuth; -alias MyAuth = OAuth2Auth< +alias MyAuth = OAuth2Auth< Flows = [ { type: OAuth2FlowType.implicit;