myc_http_tools/providers/google/
endpoints.rs1use super::{
2 functions::{get_google_user, request_token},
3 models::{QueryCode, TokenClaims},
4};
5use crate::models::auth_config::AuthConfig;
6
7use actix_web::{
8 cookie::{time::Duration as ActixWebDuration, Cookie},
9 get, web, HttpResponse, Responder,
10};
11use chrono::{prelude::*, Duration};
12use jsonwebtoken::{encode, EncodingKey, Header};
13use myc_config::optional_config::OptionalConfig;
14use reqwest::header::LOCATION;
15
16pub fn configure(conf: &mut web::ServiceConfig) {
17 conf.service(google_callback_url);
18}
19
20#[utoipa::path(
25 get,
26 responses(
27 (
28 status = 200,
29 description = "Redirect user to auth url",
30 )
31 ),
32 security(())
33)]
34#[get("/callback")]
35pub async fn google_callback_url(
36 query: web::Query<QueryCode>,
37 data: web::Data<AuthConfig>,
38) -> impl Responder {
39 let code = &query.code;
40 let state = &query.state;
41
42 if code.is_empty() {
43 return HttpResponse::Unauthorized().json(serde_json::json!({
44 "status": "fail",
45 "message": "Authorization code not provided!"
46 }));
47 }
48
49 let token_response = match request_token(code.as_str(), &data).await {
50 Err(err) => {
51 return HttpResponse::BadGateway().json(serde_json::json!({
52 "status": "fail",
53 "message": err.to_string()
54 }));
55 }
56 Ok(res) => res,
57 };
58
59 let google_user = match get_google_user(
60 &token_response.access_token,
61 &token_response.id_token,
62 )
63 .await
64 {
65 Err(err) => {
66 return HttpResponse::BadGateway().json(serde_json::json!({
67 "status": "fail",
68 "message": err.to_string(),
69 }));
70 }
71 Ok(res) => res,
72 };
73
74 let config = match data.as_ref().google.to_owned() {
75 OptionalConfig::Disabled => {
76 return HttpResponse::BadGateway().json(serde_json::json!({
77 "status": "fail",
78 "message": "Google Oauth2 is disabled!"
79 }));
80 }
81 OptionalConfig::Enabled(config) => config,
82 };
83
84 let jwt_max_age = match config.jwt_max_age.async_get_or_error().await {
85 Ok(age) => age,
86 Err(err) => {
87 return HttpResponse::BadGateway().json(serde_json::json!({
88 "status": "fail",
89 "message": err.to_string()
90 }));
91 }
92 };
93
94 let jwt_secret = match config.jwt_secret.async_get_or_error().await {
95 Ok(secret) => secret,
96 Err(err) => {
97 return HttpResponse::BadGateway().json(serde_json::json!({
98 "status": "fail",
99 "message": err.to_string()
100 }));
101 }
102 };
103
104 let client_origin = match config.client_origin.async_get_or_error().await {
105 Ok(origin) => origin,
106 Err(err) => {
107 return HttpResponse::BadGateway().json(serde_json::json!({
108 "status": "fail",
109 "message": err.to_string()
110 }));
111 }
112 };
113
114 let now = Utc::now();
115 let iat = now.timestamp() as usize;
116 let exp = (now + Duration::minutes(jwt_max_age)).timestamp() as usize;
117
118 let claims = TokenClaims {
119 sub: google_user.id.to_owned(),
120 exp,
121 iat,
122 iss: "https://accounts.google.com".to_string(),
123 id: google_user.id.to_owned(),
124 email: google_user.email.to_owned(),
125 verified_email: google_user.verified_email.to_owned(),
126 name: google_user.name.to_owned(),
127 given_name: google_user.given_name.to_owned(),
128 family_name: google_user.family_name.to_owned(),
129 picture: google_user.picture.to_owned(),
130 locale: google_user.locale.to_owned(),
131 };
132
133 let token = match encode(
134 &Header::default(),
135 &claims,
136 &EncodingKey::from_secret(jwt_secret.as_ref()),
137 ) {
138 Ok(token) => token,
139 Err(err) => {
140 tracing::debug!("Error encoding token: {:?}", err);
141 return HttpResponse::BadGateway().json(serde_json::json!({
142 "status": "fail",
143 "message": "Error encoding token"
144 }));
145 }
146 };
147
148 HttpResponse::Ok()
149 .append_header((
150 LOCATION,
151 format!("{}{}", client_origin.to_owned(), state),
152 ))
153 .cookie(
154 Cookie::build("token", token.to_owned())
155 .path("/")
156 .max_age(ActixWebDuration::new(60 * jwt_max_age, 0))
157 .http_only(true)
158 .finish(),
159 )
160 .json(serde_json::json!({
161 "status": "success",
162 "token": token
163 }))
164}