mirror of
https://github.com/OMGeeky/yup-oauth2.git
synced 2025-12-26 16:27:25 +01:00
feat(Authenticator client): Accept custom connectors
Update Authenticator to accept clients with custom connectors, rather than depending on the sealed hyper::client::connect::Connect trait, as recommended by hyper: https://docs.rs/hyper/0.13.8/src/hyper/client/connect/mod.rs.html#256-258 Closes #177.
This commit is contained in:
@@ -49,6 +49,7 @@ serde = {version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0"
|
||||
time = { version = "0.3.7", features = ["local-offset", "serde"] }
|
||||
tokio = { version = "1.0", features = ["fs", "macros", "io-std", "io-util", "time", "sync", "rt"] }
|
||||
tower-service = "^0.3.1"
|
||||
url = "2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -5,12 +5,22 @@
|
||||
//!
|
||||
//! It is also a better use of resources (memory, sockets, etc.)
|
||||
|
||||
async fn r#use<C>(
|
||||
client: hyper::Client<C>,
|
||||
authenticator: yup_oauth2::authenticator::Authenticator<C>,
|
||||
use std::error::Error as StdError;
|
||||
|
||||
use hyper::client::connect::Connection;
|
||||
use http::Uri;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
|
||||
async fn r#use<S>(
|
||||
client: hyper::Client<S>,
|
||||
authenticator: yup_oauth2::authenticator::Authenticator<S>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
|
||||
where
|
||||
C: Clone + Send + Sync + hyper::client::connect::Connect + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let token = authenticator.token(&["email"]).await?;
|
||||
let request = http::Request::get("https://example.com")
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use crate::error::Error;
|
||||
use crate::types::TokenInfo;
|
||||
use hyper::client::connect::Connection;
|
||||
use std::error::Error as StdError;
|
||||
use http::Uri;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
|
||||
/// Provide options for the Application Default Credential Flow, mostly used for testing
|
||||
#[derive(Default, Clone, Debug)]
|
||||
@@ -18,14 +23,17 @@ impl ApplicationDefaultCredentialsFlow {
|
||||
ApplicationDefaultCredentialsFlow { metadata_url }
|
||||
}
|
||||
|
||||
pub(crate) async fn token<C, T>(
|
||||
pub(crate) async fn token<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let scope = crate::helper::join(scopes, ",");
|
||||
let token_uri = format!("{}?scopes={}", self.metadata_url, scope);
|
||||
|
||||
@@ -16,14 +16,19 @@ use crate::types::{AccessToken, ApplicationSecret, TokenInfo};
|
||||
use private::AuthFlow;
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use http::{Uri};
|
||||
use hyper::client::connect::Connection;
|
||||
use std::borrow::Cow;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
|
||||
struct InnerAuthenticator<C> {
|
||||
hyper_client: hyper::Client<C>,
|
||||
struct InnerAuthenticator<S> {
|
||||
hyper_client: hyper::Client<S>,
|
||||
storage: Storage,
|
||||
auth_flow: AuthFlow,
|
||||
}
|
||||
@@ -31,8 +36,8 @@ struct InnerAuthenticator<C> {
|
||||
/// Authenticator is responsible for fetching tokens, handling refreshing tokens,
|
||||
/// and optionally persisting tokens to disk.
|
||||
#[derive(Clone)]
|
||||
pub struct Authenticator<C> {
|
||||
inner: Arc<InnerAuthenticator<C>>,
|
||||
pub struct Authenticator<S> {
|
||||
inner: Arc<InnerAuthenticator<S>>,
|
||||
}
|
||||
|
||||
struct DisplayScopes<'a, T>(&'a [T]);
|
||||
@@ -54,9 +59,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Authenticator<C>
|
||||
impl<S> Authenticator<S>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
/// Return the current token for the provided scopes.
|
||||
pub async fn token<'a, T>(&'a self, scopes: &'a [T]) -> Result<AccessToken, Error>
|
||||
@@ -669,6 +677,7 @@ impl<C> AuthenticatorBuilder<C, AuthorizedUserFlow> {
|
||||
mod private {
|
||||
use crate::application_default_credentials::ApplicationDefaultCredentialsFlow;
|
||||
use crate::authorized_user::AuthorizedUserFlow;
|
||||
use crate::authenticator::{AsyncRead, AsyncWrite, Connection, Service, StdError, Uri};
|
||||
use crate::device::DeviceFlow;
|
||||
use crate::error::Error;
|
||||
use crate::installed::InstalledFlow;
|
||||
@@ -697,14 +706,17 @@ mod private {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn token<'a, C, T>(
|
||||
pub(crate) async fn token<'a, S, T>(
|
||||
&'a self,
|
||||
hyper_client: &'a hyper::Client<C>,
|
||||
hyper_client: &'a hyper::Client<S>,
|
||||
scopes: &'a [T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
match self {
|
||||
AuthFlow::DeviceFlow(device_flow) => device_flow.token(hyper_client, scopes).await,
|
||||
@@ -729,7 +741,7 @@ mod private {
|
||||
/// A trait implemented for any hyper::Client as well as the DefaultHyperClient.
|
||||
pub trait HyperClientBuilder {
|
||||
/// The hyper connector that the resulting hyper client will use.
|
||||
type Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static;
|
||||
type Connector: Service<Uri> + Clone + Send + Sync + 'static;
|
||||
|
||||
/// Create a hyper::Client
|
||||
fn build_hyper_client(self) -> hyper::Client<Self::Connector>;
|
||||
@@ -809,13 +821,16 @@ impl HyperClientBuilder for DefaultHyperClient {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> HyperClientBuilder for hyper::Client<C>
|
||||
impl<S> HyperClientBuilder for hyper::Client<S>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
type Connector = C;
|
||||
type Connector = S;
|
||||
|
||||
fn build_hyper_client(self) -> hyper::Client<C> {
|
||||
fn build_hyper_client(self) -> hyper::Client<S> {
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
//!
|
||||
use crate::error::Error;
|
||||
use crate::types::TokenInfo;
|
||||
use hyper::client::connect::Connection;
|
||||
use hyper::header;
|
||||
use http::Uri;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error as StdError;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
use url::form_urlencoded;
|
||||
|
||||
const TOKEN_URI: &str = "https://accounts.google.com/o/oauth2/token";
|
||||
@@ -37,14 +42,17 @@ pub struct AuthorizedUserFlow {
|
||||
|
||||
impl AuthorizedUserFlow {
|
||||
/// Send a request for a new Bearer token to the OAuth provider.
|
||||
pub(crate) async fn token<C, T>(
|
||||
pub(crate) async fn token<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
_scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let req = form_urlencoded::Serializer::new(String::new())
|
||||
.extend_pairs(&[
|
||||
|
||||
@@ -5,10 +5,15 @@ use crate::error::{AuthError, Error};
|
||||
use crate::types::{ApplicationSecret, TokenInfo};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::error::Error as StdError;
|
||||
use std::time::Duration;
|
||||
|
||||
use hyper::client::connect::Connection;
|
||||
use hyper::header;
|
||||
use http::Uri;
|
||||
use url::form_urlencoded;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
|
||||
pub const GOOGLE_DEVICE_CODE_URL: &str = "https://accounts.google.com/o/oauth2/device/code";
|
||||
|
||||
@@ -38,14 +43,17 @@ impl DeviceFlow {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn token<C, T>(
|
||||
pub(crate) async fn token<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let device_auth_resp = Self::request_code(
|
||||
&self.app_secret,
|
||||
@@ -67,15 +75,18 @@ impl DeviceFlow {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn wait_for_device_token<C>(
|
||||
async fn wait_for_device_token<S>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
app_secret: &ApplicationSecret,
|
||||
device_auth_resp: &DeviceAuthResponse,
|
||||
grant_type: &str,
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let mut interval = device_auth_resp.interval;
|
||||
log::debug!("Polling every {:?} for device token", interval);
|
||||
@@ -124,15 +135,18 @@ impl DeviceFlow {
|
||||
/// * If called after a successful result was returned at least once.
|
||||
/// # Examples
|
||||
/// See test-cases in source code for a more complete example.
|
||||
async fn request_code<C, T>(
|
||||
async fn request_code<S, T>(
|
||||
application_secret: &ApplicationSecret,
|
||||
client: &hyper::Client<C>,
|
||||
client: &hyper::Client<S>,
|
||||
device_code_url: &str,
|
||||
scopes: &[T],
|
||||
) -> Result<DeviceAuthResponse, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let req = form_urlencoded::Serializer::new(String::new())
|
||||
.extend_pairs(&[
|
||||
@@ -172,14 +186,17 @@ impl DeviceFlow {
|
||||
///
|
||||
/// # Examples
|
||||
/// See test-cases in source code for a more complete example.
|
||||
async fn poll_token<'a, C>(
|
||||
async fn poll_token<'a, S>(
|
||||
application_secret: &ApplicationSecret,
|
||||
client: &hyper::Client<C>,
|
||||
client: &hyper::Client<S>,
|
||||
device_code: &str,
|
||||
grant_type: &str,
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
// We should be ready for a new request
|
||||
let req = form_urlencoded::Serializer::new(String::new())
|
||||
|
||||
@@ -8,12 +8,17 @@ use crate::types::{ApplicationSecret, TokenInfo};
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use std::convert::AsRef;
|
||||
use std::error::Error as StdError;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hyper::client::connect::Connection;
|
||||
use hyper::header;
|
||||
use http::Uri;
|
||||
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::sync::oneshot;
|
||||
use tower_service::Service;
|
||||
use url::form_urlencoded;
|
||||
|
||||
const QUERY_SET: AsciiSet = CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>');
|
||||
@@ -100,14 +105,17 @@ impl InstalledFlow {
|
||||
/// . Return that token
|
||||
///
|
||||
/// It's recommended not to use the DefaultInstalledFlowDelegate, but a specialized one.
|
||||
pub(crate) async fn token<C, T>(
|
||||
pub(crate) async fn token<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
match self.method {
|
||||
InstalledFlowReturnMethod::HTTPRedirect => {
|
||||
@@ -121,15 +129,18 @@ impl InstalledFlow {
|
||||
}
|
||||
}
|
||||
|
||||
async fn ask_auth_code_interactively<C, T>(
|
||||
async fn ask_auth_code_interactively<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
app_secret: &ApplicationSecret,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let url = build_authentication_request_url(
|
||||
&app_secret.auth_uri,
|
||||
@@ -148,15 +159,18 @@ impl InstalledFlow {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn ask_auth_code_via_http<C, T>(
|
||||
async fn ask_auth_code_via_http<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
app_secret: &ApplicationSecret,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
use std::borrow::Cow;
|
||||
let server = InstalledFlowServer::run()?;
|
||||
@@ -185,15 +199,18 @@ impl InstalledFlow {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn exchange_auth_code<C>(
|
||||
async fn exchange_auth_code<S>(
|
||||
&self,
|
||||
authcode: &str,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
app_secret: &ApplicationSecret,
|
||||
server_addr: Option<SocketAddr>,
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let redirect_uri = self.flow_delegate.redirect_uri();
|
||||
let request = Self::request_token(app_secret, authcode, redirect_uri, server_addr);
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use crate::error::Error;
|
||||
use crate::types::{ApplicationSecret, TokenInfo};
|
||||
|
||||
use http::{Uri};
|
||||
use hyper::client::connect::Connection;
|
||||
use hyper::header;
|
||||
use std::error::Error as StdError;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
use url::form_urlencoded;
|
||||
|
||||
/// Implements the [OAuth2 Refresh Token Flow](https://developers.google.com/youtube/v3/guides/authentication#devices).
|
||||
@@ -26,13 +31,16 @@ impl RefreshFlow {
|
||||
///
|
||||
/// # Examples
|
||||
/// Please see the crate landing page for an example.
|
||||
pub(crate) async fn refresh_token<C>(
|
||||
client: &hyper::Client<C>,
|
||||
pub(crate) async fn refresh_token<S>(
|
||||
client: &hyper::Client<S>,
|
||||
client_secret: &ApplicationSecret,
|
||||
refresh_token: &str,
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
log::debug!(
|
||||
"refreshing access token with refresh token: {}",
|
||||
|
||||
@@ -16,15 +16,19 @@
|
||||
use crate::error::Error;
|
||||
use crate::types::TokenInfo;
|
||||
|
||||
use std::{io, path::PathBuf};
|
||||
use std::{io, path::PathBuf, error::Error as StdError};
|
||||
|
||||
use hyper::client::connect::Connection;
|
||||
use hyper::header;
|
||||
use http::Uri;
|
||||
use rustls::{
|
||||
self,
|
||||
sign::{self, SigningKey},
|
||||
PrivateKey,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tower_service::Service;
|
||||
use time::OffsetDateTime;
|
||||
use url::form_urlencoded;
|
||||
|
||||
@@ -193,14 +197,17 @@ impl ServiceAccountFlow {
|
||||
}
|
||||
|
||||
/// Send a request for a new Bearer token to the OAuth provider.
|
||||
pub(crate) async fn token<C, T>(
|
||||
pub(crate) async fn token<S, T>(
|
||||
&self,
|
||||
hyper_client: &hyper::Client<C>,
|
||||
hyper_client: &hyper::Client<S>,
|
||||
scopes: &[T],
|
||||
) -> Result<TokenInfo, Error>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
|
||||
S: Service<Uri> + Clone + Send + Sync + 'static,
|
||||
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
S::Future: Send + Unpin + 'static,
|
||||
S::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||
{
|
||||
let claims = Claims::new(&self.key, scopes, self.subject.as_deref());
|
||||
let signed = self.signer.sign_claims(&claims).map_err(|_| {
|
||||
|
||||
Reference in New Issue
Block a user