-
Notifications
You must be signed in to change notification settings - Fork 9
Description
Many thanks for all your hard work on elm-open-api, it's much appreciated! Further to our discussion on Elm Discourse, here's information regarding the problem and the solution I've implemented.
Description
When trying to generate code for an API that uses OAuth2 for security, the following error is generated:
Warning: Todo: Unsupported security schema: Oauth2
at /users/me/ -> GETTo Reproduce
To reproduce this, add the following to the security section of your openapi.json schema file:
"securitySchemes": {
"OAuth2PasswordBearer": {
"type": "oauth2",
"flows": {
"password": {
"scopes": {},
"tokenUrl": "token"
}
}
}
}Additionally, here is the full openapi.json file that I'm currently using:
Full openapi.json file
{
"openapi": "3.1.0",
"info": {
"title": "Paracosm API",
"summary": "Web API for the `paracosm` framework.",
"version": "0.1.0"
},
"servers": [
{
"url": "http://127.0.0.1:8000",
"description": "Development environment"
}
],
"paths": {
"/token": {
"post": {
"summary": "Log in to get access token for API through docs..",
"operationId": "login_for_docs_token_post",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/Body_login_for_docs_token_post"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Token"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/json-token": {
"post": {
"summary": "Log in to get access token for API.",
"operationId": "login_json_token_post",
"parameters": [
{
"name": "username",
"in": "query",
"required": true,
"schema": {
"type": "string",
"title": "Username"
}
},
{
"name": "password",
"in": "query",
"required": true,
"schema": {
"type": "string",
"title": "Password"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Token"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/users/": {
"post": {
"summary": "Create a new user.",
"operationId": "create_user_users__post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserCreate"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserPublic"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/users/me/": {
"get": {
"summary": "Get current user information.",
"operationId": "me_users_me__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserPublic"
}
}
}
}
},
"security": [
{
"OAuth2PasswordBearer": []
}
]
}
}
},
"components": {
"schemas": {
"Body_login_for_docs_token_post": {
"properties": {
"grant_type": {
"anyOf": [
{
"type": "string",
"pattern": "password"
},
{
"type": "null"
}
],
"title": "Grant Type"
},
"username": {
"type": "string",
"title": "Username"
},
"password": {
"type": "string",
"title": "Password"
},
"scope": {
"type": "string",
"title": "Scope",
"default": ""
},
"client_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Client Id"
},
"client_secret": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Client Secret"
}
},
"type": "object",
"required": [
"username",
"password"
],
"title": "Body_login_for_docs_token_post"
},
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"Token": {
"properties": {
"access_token": {
"type": "string",
"title": "Access Token"
},
"token_type": {
"type": "string",
"title": "Token Type"
}
},
"type": "object",
"required": [
"access_token",
"token_type"
],
"title": "Token"
},
"UserCreate": {
"properties": {
"username": {
"type": "string",
"title": "Username"
},
"email": {
"type": "string",
"title": "Email"
},
"full_name": {
"type": "string",
"title": "Full Name"
},
"password": {
"type": "string",
"title": "Password"
},
"repeated_password": {
"type": "string",
"title": "Repeated Password"
}
},
"type": "object",
"required": [
"username",
"email",
"full_name",
"password",
"repeated_password"
],
"title": "UserCreate"
},
"UserPublic": {
"properties": {
"username": {
"type": "string",
"title": "Username"
},
"email": {
"type": "string",
"title": "Email"
},
"full_name": {
"type": "string",
"title": "Full Name"
},
"id": {
"type": "integer",
"title": "Id"
}
},
"type": "object",
"required": [
"username",
"email",
"full_name",
"id"
],
"title": "UserPublic"
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
},
"securitySchemes": {
"OAuth2PasswordBearer": {
"type": "oauth2",
"flows": {
"password": {
"scopes": {},
"tokenUrl": "token"
}
}
}
}
}
}I'm passing a json web token around for auth, and I can extend the code generated by elm-open-api relatively easily to enable authentication. For example, I can change the /users/me endpoint, which requires auth, from this:
meUsersMeGet :
{ toMsg :
Result (OpenApi.Common.Error ParacosmApi.Types.MeUsersMeGet_Error String) ParacosmApi.Types.UserPublic
-> msg
}
-> Cmd msg
meUsersMeGet config =
Http.request
{ url = "http://127.0.0.1:8000/users/me/"
, method = "GET"
, headers = []
, expect =
OpenApi.Common.expectJsonCustom
config.toMsg
(Dict.fromList [])
ParacosmApi.Json.decodeUserPublic
, body = Http.emptyBody
, timeout = Nothing
, tracker = Nothing
}to this:
meUsersMeGet :
{ toMsg :
Result (OpenApi.Common.Error ParacosmApi.Types.MeUsersMeGet_Error String) ParacosmApi.Types.UserPublic
-> msg
-- Next line changed
, token : ParacosmApi.Types.Token
}
-> Cmd msg
meUsersMeGet config =
Http.request
{ url = "http://127.0.0.1:8000/users/me/"
, method = "GET"
-- Next line changed
, headers = [ Http.header "Authorization" ("Bearer " ++ config.token.access_token) ]
, expect =
OpenApi.Common.expectJsonCustom
config.toMsg
(Dict.fromList [])
ParacosmApi.Json.decodeUserPublic
, body = Http.emptyBody
, timeout = Nothing
, tracker = Nothing
}And the API works as expected.
Additional Context
I am a novice when it comes to making OpenAPI compliant APIs, so there's a good chance some of the configuration is wrong on my end. I followed this section of the FastAPI docs to get to this point: https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/