Skip to main content

openauth_plugins/device_authorization/
mod.rs

1//! OAuth 2.0 device authorization plugin.
2
3mod errors;
4mod options;
5mod routes;
6mod schema;
7mod store;
8
9use std::sync::Arc;
10
11use openauth_core::plugin::AuthPlugin;
12
13pub use errors::{
14    ACCESS_DENIED, AUTHENTICATION_REQUIRED, AUTHORIZATION_PENDING, DEVICE_CODE_ALREADY_PROCESSED,
15    EXPIRED_DEVICE_CODE, EXPIRED_USER_CODE, FAILED_TO_CREATE_SESSION, INVALID_DEVICE_CODE,
16    INVALID_DEVICE_CODE_STATUS, INVALID_USER_CODE, POLLING_TOO_FREQUENTLY, USER_NOT_FOUND,
17};
18pub use options::{
19    DeviceAuthorizationOptions, DeviceAuthorizationOptionsError, DeviceAuthorizationSchemaFields,
20    DeviceAuthorizationSchemaOptions,
21};
22pub use routes::{
23    DeviceApprovalRequest, DeviceCodeRequest, DeviceCodeResponse, DeviceTokenRequest,
24    DeviceTokenResponse, DeviceVerificationResponse,
25};
26pub use store::{DeviceAuthorizationStatus, DeviceCodeRecord};
27
28pub const UPSTREAM_PLUGIN_ID: &str = "device-authorization";
29
30/// Build the device authorization plugin with default options.
31pub fn device_authorization() -> AuthPlugin {
32    device_authorization_with_options(DeviceAuthorizationOptions::default())
33}
34
35/// Build the device authorization plugin with explicit options.
36pub fn device_authorization_with_options(options: DeviceAuthorizationOptions) -> AuthPlugin {
37    let schema_options = options.schema.clone();
38    let options = Arc::new(options);
39    let init_options = Arc::clone(&options);
40    AuthPlugin::new(UPSTREAM_PLUGIN_ID)
41        .with_version(crate::VERSION)
42        .with_init(move |_context| {
43            init_options.validate().map_err(|error| {
44                openauth_core::error::OpenAuthError::InvalidConfig(error.to_string())
45            })?;
46            Ok(Default::default())
47        })
48        .with_schema(schema::device_code_table(&schema_options))
49        .with_endpoint(routes::device_code(Arc::clone(&options)))
50        .with_endpoint(routes::device_token(Arc::clone(&options)))
51        .with_endpoint(routes::device_verify())
52        .with_endpoint(routes::device_approve())
53        .with_endpoint(routes::device_deny())
54        .with_error_code(errors::plugin_error_code(
55            INVALID_DEVICE_CODE,
56            "Invalid device code",
57        ))
58        .with_error_code(errors::plugin_error_code(
59            EXPIRED_DEVICE_CODE,
60            "Device code has expired",
61        ))
62        .with_error_code(errors::plugin_error_code(
63            EXPIRED_USER_CODE,
64            "User code has expired",
65        ))
66        .with_error_code(errors::plugin_error_code(
67            AUTHORIZATION_PENDING,
68            "Authorization pending",
69        ))
70        .with_error_code(errors::plugin_error_code(ACCESS_DENIED, "Access denied"))
71        .with_error_code(errors::plugin_error_code(
72            INVALID_USER_CODE,
73            "Invalid user code",
74        ))
75        .with_error_code(errors::plugin_error_code(
76            DEVICE_CODE_ALREADY_PROCESSED,
77            "Device code already processed",
78        ))
79        .with_error_code(errors::plugin_error_code(
80            POLLING_TOO_FREQUENTLY,
81            "Polling too frequently",
82        ))
83        .with_error_code(errors::plugin_error_code(USER_NOT_FOUND, "User not found"))
84        .with_error_code(errors::plugin_error_code(
85            FAILED_TO_CREATE_SESSION,
86            "Failed to create session",
87        ))
88        .with_error_code(errors::plugin_error_code(
89            INVALID_DEVICE_CODE_STATUS,
90            "Invalid device code status",
91        ))
92        .with_error_code(errors::plugin_error_code(
93            AUTHENTICATION_REQUIRED,
94            "Authentication required",
95        ))
96}