fxa_client/token.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! # Token Management
//!
//! A signed-in application will typically hold a number of different *tokens* associated with the
//! user's account, including:
//!
//! - An OAuth `refresh_token`, representing their ongoing connection to the account
//! and the scopes that have been granted.
//! - Short-lived OAuth `access_token`s that can be used to access resources on behalf
//! of the user.
//! - Optionally, a `session_token` that gives full control over the user's account,
//! typically managed on behalf of web content that runs within the context
//! of the application.
use crate::{ApiResult, Error, FirefoxAccount};
use error_support::handle_error;
use serde_derive::*;
use std::convert::{TryFrom, TryInto};
impl FirefoxAccount {
/// Get a short-lived OAuth access token for the user's account.
///
/// **💾 This method alters the persisted account state.**
///
/// Applications that need to access resources on behalf of the user must obtain an
/// `access_token` in order to do so. For example, an access token is required when
/// fetching the user's profile data, or when accessing their data stored in Firefox Sync.
///
/// This method will obtain and return an access token bearing the requested scopes, either
/// from a local cache of previously-issued tokens, or by creating a new one from the server.
///
/// # Arguments
///
/// - `scope` - the OAuth scope to be granted by the token.
/// - This must be one of the scopes requested during the signin flow.
/// - Only a single scope is supported; for multiple scopes request multiple tokens.
/// - `ttl` - optionally, the time for which the token should be valid, in seconds.
///
/// # Notes
///
/// - If the application receives an authorization error when trying to use the resulting
/// token, it should call [`clear_access_token_cache`](FirefoxAccount::clear_access_token_cache)
/// before requesting a fresh token.
#[handle_error(Error)]
pub fn get_access_token(&self, scope: &str, ttl: Option<i64>) -> ApiResult<AccessTokenInfo> {
// Signedness converstion for Kotlin compatibility :-/
let ttl = ttl.map(|ttl| u64::try_from(ttl).unwrap_or_default());
self.internal
.lock()
.get_access_token(scope, ttl)?
.try_into()
}
/// Get the session token for the user's account, if one is available.
///
/// **💾 This method alters the persisted account state.**
///
/// Applications that function as a web browser may need to hold on to a session token
/// on behalf of Firefox Accounts web content. This method exists so that they can retrieve
/// it an pass it back to said web content when required.
///
/// # Notes
///
/// - Please do not attempt to use the resulting token to directly make calls to the
/// Firefox Accounts servers! All account management functionality should be performed
/// in web content.
/// - A session token is only available to applications that have requested the
/// `https://identity.mozilla.com/tokens/session` scope.
#[handle_error(Error)]
pub fn get_session_token(&self) -> ApiResult<String> {
self.internal.lock().get_session_token()
}
/// Update the stored session token for the user's account.
///
/// **💾 This method alters the persisted account state.**
///
/// Applications that function as a web browser may need to hold on to a session token
/// on behalf of Firefox Accounts web content. This method exists so that said web content
/// signals that it has generated a new session token, the stored value can be updated
/// to match.
///
/// # Arguments
///
/// - `session_token` - the new session token value provided from web content.
#[handle_error(Error)]
pub fn handle_session_token_change(&self, session_token: &str) -> ApiResult<()> {
self.internal
.lock()
.handle_session_token_change(session_token)
}
/// Create a new OAuth authorization code using the stored session token.
///
/// When a signed-in application receives an incoming device pairing request, it can
/// use this method to grant the request and generate a corresponding OAuth authorization
/// code. This code would then be passed back to the connecting device over the
/// pairing channel (a process which is not currently supported by any code in this
/// component).
///
/// # Arguments
///
/// - `params` - the OAuth parameters from the incoming authorization request
#[handle_error(Error)]
pub fn authorize_code_using_session_token(
&self,
params: AuthorizationParameters,
) -> ApiResult<String> {
self.internal
.lock()
.authorize_code_using_session_token(params)
}
/// Clear the access token cache in response to an auth failure.
///
/// **💾 This method alters the persisted account state.**
///
/// Applications that receive an authentication error when trying to use an access token,
/// should call this method before creating a new token and retrying the failed operation.
/// It ensures that the expired token is removed and a fresh one generated.
pub fn clear_access_token_cache(&self) {
self.internal.lock().clear_access_token_cache()
}
}
/// An OAuth access token, with its associated keys and metadata.
///
/// This struct represents an FxA OAuth access token, which can be used to access a resource
/// or service on behalf of the user. For example, accessing the user's data in Firefox Sync
/// an access token for the scope `https://identity.mozilla.com/apps/sync` along with the
/// associated encryption key.
#[derive(Debug)]
pub struct AccessTokenInfo {
/// The scope of access granted by token.
pub scope: String,
/// The access token itself.
///
/// This is the value that should be included in the `Authorization` header when
/// accessing an OAuth protected resource on behalf of the user.
pub token: String,
/// The client-side encryption key associated with this scope.
///
/// **⚠️ Warning:** the value of this field should never be revealed outside of the
/// application. For example, it should never to sent to a server or logged in a log file.
pub key: Option<ScopedKey>,
/// The expiry time of the token, in seconds.
///
/// This is the timestamp at which the token is set to expire, in seconds since
/// unix epoch. Note that it is a signed integer, for compatibility with languages
/// that do not have an unsigned integer type.
///
/// This timestamp is for guidance only. Access tokens are not guaranteed to remain
/// value for any particular lengthof time, and consumers should be prepared to handle
/// auth failures even if the token has not yet expired.
pub expires_at: i64,
}
/// A cryptographic key associated with an OAuth scope.
///
/// Some OAuth scopes have a corresponding client-side encryption key that is required
/// in order to access protected data. This struct represents such key material in a
/// format compatible with the common "JWK" standard.
///
#[derive(Clone, Serialize, Deserialize)]
pub struct ScopedKey {
/// The type of key.
///
/// In practice for FxA, this will always be string string "oct" (short for "octal")
/// to represent a raw symmetric key.
pub kty: String,
/// The OAuth scope with which this key is associated.
pub scope: String,
/// The key material, as base64-url-encoded bytes.
///
/// **⚠️ Warning:** the value of this field should never be revealed outside of the
/// application. For example, it should never to sent to a server or logged in a log file.
pub k: String,
/// An opaque unique identifier for this key.
///
/// Unlike the `k` field, this value is not secret and may be revealed to the server.
pub kid: String,
}
/// Parameters provided in an incoming OAuth request.
///
/// This struct represents parameters obtained from an incoming OAuth request - that is,
/// the values that an OAuth client would append to the authorization URL when initiating
/// an OAuth sign-in flow.
pub struct AuthorizationParameters {
pub client_id: String,
pub scope: Vec<String>,
pub state: String,
pub access_type: String,
pub code_challenge: Option<String>,
pub code_challenge_method: Option<String>,
pub keys_jwk: Option<String>,
}