diff --git a/config/rest.php b/config/rest.php index 06f54f6..edafd33 100644 --- a/config/rest.php +++ b/config/rest.php @@ -65,8 +65,8 @@ ], 'info' => [ 'title' => config('app.name'), - 'summary' => 'This is my projet\'s documentation', - 'description' => 'Find out all about my projet\'s API', + 'summary' => 'This is my project\'s documentation', + 'description' => 'Find out all about my project\'s API', 'termsOfService' => null, // (Optional) Url to terms of services 'contact' => [ 'name' => 'My Company', @@ -103,23 +103,89 @@ ], // See https://spec.openapis.org/oas/v3.1.0#security-scheme-object 'security' => [ - // [ - // 'type' => 'http', - // 'description' => 'description', - // 'scheme' => 'Bearer', - // 'bearerFormat' => 'JWT' - // ], - // [ - // 'type' => 'oauth2', - // 'flows' => [ - // 'authorizationCode' => [ - // 'scopes' => ['write:pets'], - // 'tokenUrl' => 'https://example.com/api/oauth/token', - // 'authorizationUrl' => 'https://example.com/api/oauth/dialog', - // 'refreshUrl' => 'https://example.com/api/oauth/refresh', - // ] - // ] - // ] + // [ + // "api_key" => [] + // ], + // [ + // "auth" => [ + // 'write:users', + // 'read:users' + // ] + // ] + ], + // See https://spec.openapis.org/oas/v3.1.0#security-scheme-object + 'securitySchemes' => [ + // "api_key" => [ + // "description" => "Authentication via API key", + // "type" => "apiKey", + // "name" => "x-api-key", + // "in" => "header" + // ], + // "http_bearer" => [ + // "description" => "HTTP authentication with bearer token", + // "type" => "http", + // "scheme" => "bearer", + // "bearerFormat" => "JWT" + // ], + // "oauth_authcode" => [ + // "description" => "Authentication via OAuth2 with authorization code flow", + // "type" => "oauth2", + // "flows" => [ + // "authorizationCode" => [ + // "authorizationUrl" => "https://example.com/api/oauth/dialog", + // "tokenUrl" => "https://example.com/api/oauth/token", + // "refreshUrl" => "https://example.com/api/oauth/refresh", + // "scopes" => [ + // "do:something" => "do something" + // ] + // ] + // ] + // ], + // "oauth_clientcredentials" => [ + // "description" => "Authentication via OAuth2 with client credentials flow", + // "type" => "oauth2", + // "flows" => [ + // "clientCredentials" => [ + // "tokenUrl" => "https://example.com/api/oauth/token", + // "refreshUrl" => "https://example.com/api/oauth/refresh", + // "scopes" => [ + // "do:something" => "do something" + // ] + // ] + // ] + // ], + // "oauth_implicit" => [ + // "description" => "Authentication via OAuth2 with implicit flow", + // "type" => "oauth2", + // "flows" => [ + // "implicit" => [ + // "authorizationUrl" => "https://example.com/api/oauth/dialog", + // "refreshUrl" => "https://example.com/api/oauth/refresh", + // "scopes" => [ + // "write:foo" => "modify foo", + // "read:foo" => "read foo" + // ] + // ] + // ] + // ], + // "oauth_password" => [ + // "description" => "Authentication via OAuth2 with resource owner password flow", + // "type" => "oauth2", + // "flows" => [ + // "password" => [ + // "tokenUrl" => "https://example.com/api/oauth/token", + // "refreshUrl" => "https://example.com/api/oauth/refresh", + // "scopes" => [ + // "do:something" => "do something" + // ] + // ] + // ] + // ], + // "open_id" => [ + // "description" => "Authentication via OpenID Connect", + // "type" => "openIdConnect", + // "openIdConnectUrl" => "https://example.com/openid/issuer/location" + // ] ], ], ]; diff --git a/src/Documentation/Schemas/OpenAPI.php b/src/Documentation/Schemas/OpenAPI.php index 1b27335..b3cff6c 100644 --- a/src/Documentation/Schemas/OpenAPI.php +++ b/src/Documentation/Schemas/OpenAPI.php @@ -44,6 +44,13 @@ class OpenAPI extends Schema */ protected array $security = []; + /** + * A declaration of which security schemes mechanisms can be used across the API. + * + * @var array + */ + protected array $securitySchemes = []; + /** * Get the version number of the OpenAPI specification. * @@ -140,6 +147,30 @@ public function withSecurity(array $security): self return $this; } + /** + * Get the declaration of security mechanisms for the API. + * + * @return array + */ + public function securitySchemes(): array + { + return $this->securitySchemes; + } + + /** + * Set the declaration of security mechanisms for the API. + * + * @param array $securitySchemes + * + * @return self + */ + public function withSecuritySchemes(array $securitySchemes): self + { + $this->securitySchemes = $securitySchemes; + + return $this; + } + /** * Set the Server Objects, which provide connectivity information to a target server. * @@ -178,7 +209,10 @@ public function jsonSerialize(): mixed 'paths' => collect($this->paths())->map->jsonSerialize()->toArray(), ], isset($this->servers) ? ['servers' => collect($this->servers())->map->jsonSerialize()->toArray()] : [], - isset($this->security) ? ['security' => collect($this->security())->map->jsonSerialize()->toArray()] : [] + isset($this->security) ? ['security' => $this->security] : [], + ['components' => array_merge( + isset($this->securitySchemes) ? ['securitySchemes' => collect($this->securitySchemes())->map->jsonSerialize()->toArray()] : [] + )] ); } @@ -207,30 +241,30 @@ public function generate(): OpenAPI $servers[] = $serverInstance; } - $securities = []; - - foreach (config('rest.documentation.security') as $security) { - $securityInstance = (new SecurityScheme()) - ->withDescription($security['description'] ?? '') - ->withIn($security['in'] ?? '') - ->withType($security['type'] ?? '') - ->withName($security['name'] ?? '') - ->withBearerFormat($security['bearerFormat'] ?? '') - ->withOpenIdConnectUrl($security['openIdConnectUrl'] ?? '') - ->withScheme($security['scheme'] ?? '') + $securitySchemes = []; + + foreach (config('rest.documentation.securitySchemes') as $securitySchemeKey => $securityScheme) { + $securitySchemeInstance = (new SecurityScheme()) + ->withDescription($securityScheme['description'] ?? '') + ->withIn($securityScheme['in'] ?? '') + ->withType($securityScheme['type'] ?? '') + ->withName($securityScheme['name'] ?? '') + ->withBearerFormat($securityScheme['bearerFormat'] ?? '') + ->withOpenIdConnectUrl($securityScheme['openIdConnectUrl'] ?? '') + ->withScheme($securityScheme['scheme'] ?? '') ->withFlows($oauthFlows = new OauthFlows()); - foreach ($security['flows'] ?? [] as $key => $flow) { + foreach ($securityScheme['flows'] ?? [] as $key => $flow) { $flowInstance = (new OauthFlow()) ->withScopes($flow['scopes'] ?? []) ->withAuthorizationUrl($flow['authorizationUrl'] ?? '') - ->withTokenUrl($flow['tokenUrl']) - ->withRefreshUrl($flow['refreshUrl']); + ->withTokenUrl($flow['tokenUrl'] ?? '') + ->withRefreshUrl($flow['refreshUrl'] ?? ''); $oauthFlows->{'with'.Str::studly($key)}($flowInstance); } - $securities[] = $securityInstance; + $securitySchemes[$securitySchemeKey] = $securitySchemeInstance; } return Rest::applyDocumentationCallback( @@ -242,7 +276,8 @@ public function generate(): OpenAPI ->withPaths( $this->generatePaths() ) - ->withSecurity($securities) + ->withSecuritySchemes($securitySchemes) + ->withSecurity(config('rest.documentation.security')) ->withServers($servers) ); }