openauth-plugins 0.0.4

Official OpenAuth plugin modules.
Documentation
use openauth_core::api::OpenApiOperation;
use serde_json::{json, Value};

const TAG: &str = "Device Authorization";

pub fn device_code_operation() -> OpenApiOperation {
    OpenApiOperation::new("deviceCode")
        .description("Create an OAuth 2.0 device authorization request.")
        .tag(TAG)
        .request_body(request_body(json!({
            "type": "object",
            "properties": {
                "client_id": { "type": "string" },
                "scope": { "type": "string" },
            },
            "required": ["client_id"],
        })))
        .response(
            "200",
            response("Device authorization code response.", device_code_schema()),
        )
        .response(
            "400",
            response("OAuth device-flow error response.", error_schema()),
        )
}

pub fn device_token_operation() -> OpenApiOperation {
    OpenApiOperation::new("deviceToken")
        .description("Exchange an approved OAuth 2.0 device code for a bearer token.")
        .tag(TAG)
        .request_body(request_body(json!({
            "type": "object",
            "properties": {
                "grant_type": { "type": "string" },
                "device_code": { "type": "string" },
                "client_id": { "type": "string" },
            },
            "required": ["grant_type", "device_code", "client_id"],
        })))
        .response(
            "200",
            response("OAuth bearer token response.", token_schema()),
        )
        .response(
            "400",
            response("OAuth device-flow error response.", error_schema()),
        )
}

pub fn device_verify_operation() -> OpenApiOperation {
    OpenApiOperation::new("deviceVerify")
        .description("Look up a device authorization request by user code.")
        .tag(TAG)
        .parameter(json!({
            "name": "user_code",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
        }))
        .response(
            "200",
            response("Device verification response.", verification_schema()),
        )
        .response(
            "400",
            response("OAuth device-flow error response.", error_schema()),
        )
}

pub fn device_decision_operation(operation_id: &str, description: &str) -> OpenApiOperation {
    OpenApiOperation::new(operation_id)
        .description(description)
        .tag(TAG)
        .request_body(request_body(json!({
            "type": "object",
            "properties": {
                "userCode": { "type": "string" },
            },
            "required": ["userCode"],
        })))
        .response(
            "200",
            response("Device authorization decision response.", success_schema()),
        )
        .response(
            "400",
            response("OAuth device-flow error response.", error_schema()),
        )
        .response(
            "401",
            response("OAuth device-flow error response.", error_schema()),
        )
        .response(
            "403",
            response("OAuth device-flow error response.", error_schema()),
        )
}

fn request_body(schema: Value) -> Value {
    json!({
        "required": true,
        "content": {
            "application/json": {
                "schema": schema,
            },
            "application/x-www-form-urlencoded": {
                "schema": schema,
            },
        },
    })
}

fn response(description: &str, schema: Value) -> Value {
    json!({
        "description": description,
        "content": {
            "application/json": {
                "schema": schema,
            },
        },
    })
}

fn device_code_schema() -> Value {
    json!({
        "type": "object",
        "properties": {
            "device_code": { "type": "string" },
            "user_code": { "type": "string" },
            "verification_uri": { "type": "string" },
            "verification_uri_complete": { "type": "string" },
            "expires_in": { "type": "integer" },
            "interval": { "type": "integer" },
        },
        "required": [
            "device_code",
            "user_code",
            "verification_uri",
            "verification_uri_complete",
            "expires_in",
            "interval"
        ],
    })
}

fn token_schema() -> Value {
    json!({
        "type": "object",
        "properties": {
            "access_token": { "type": "string" },
            "token_type": { "type": "string" },
            "expires_in": { "type": "integer" },
            "scope": { "type": "string" },
        },
        "required": ["access_token", "token_type", "expires_in", "scope"],
    })
}

fn verification_schema() -> Value {
    json!({
        "type": "object",
        "properties": {
            "user_code": { "type": "string" },
            "status": { "type": "string" },
        },
        "required": ["user_code", "status"],
    })
}

fn success_schema() -> Value {
    json!({
        "type": "object",
        "properties": {
            "success": { "type": "boolean" },
        },
        "required": ["success"],
    })
}

fn error_schema() -> Value {
    json!({
        "type": "object",
        "properties": {
            "error": { "type": "string" },
            "error_description": { "type": "string" },
        },
        "required": ["error", "error_description"],
    })
}