fxa_client/
token.rs

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