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::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 /// - `use_cache` - optionally set to false to force a new token request. The fetched
41 /// token will still be cached for later `get_access_token` calls.
42 ///
43 /// # Notes
44 ///
45 /// - If the application receives an authorization error when trying to use the resulting
46 /// token, it should call [`clear_access_token_cache`](FirefoxAccount::clear_access_token_cache)
47 /// before requesting a fresh token.
48 #[handle_error(Error)]
49 pub fn get_access_token(&self, scope: &str, use_cache: bool) -> ApiResult<AccessTokenInfo> {
50 self.internal
51 .lock()
52 .get_access_token(scope, use_cache)?
53 .try_into()
54 }
55
56 /// Get the session token for the user's account, if one is available.
57 ///
58 /// **💾 This method alters the persisted account state.**
59 ///
60 /// Applications that function as a web browser may need to hold on to a session token
61 /// on behalf of Firefox Accounts web content. This method exists so that they can retrieve
62 /// it an pass it back to said web content when required.
63 ///
64 /// # Notes
65 ///
66 /// - Please do not attempt to use the resulting token to directly make calls to the
67 /// Firefox Accounts servers! All account management functionality should be performed
68 /// in web content.
69 /// - A session token is only available to applications that have requested the
70 /// `https://identity.mozilla.com/tokens/session` scope.
71 #[handle_error(Error)]
72 pub fn get_session_token(&self) -> ApiResult<String> {
73 self.internal.lock().get_session_token()
74 }
75
76 /// Update the stored session token for the user's account.
77 ///
78 /// **💾 This method alters the persisted account state.**
79 ///
80 /// Applications that function as a web browser may need to hold on to a session token
81 /// on behalf of Firefox Accounts web content. This method exists so that said web content
82 /// signals that it has generated a new session token, the stored value can be updated
83 /// to match.
84 ///
85 /// # Arguments
86 ///
87 /// - `session_token` - the new session token value provided from web content.
88 #[handle_error(Error)]
89 pub fn handle_session_token_change(&self, session_token: &str) -> ApiResult<()> {
90 self.internal
91 .lock()
92 .handle_session_token_change(session_token)
93 }
94
95 /// Create a new OAuth authorization code using the stored session token.
96 ///
97 /// When a signed-in application receives an incoming device pairing request, it can
98 /// use this method to grant the request and generate a corresponding OAuth authorization
99 /// code. This code would then be passed back to the connecting device over the
100 /// pairing channel (a process which is not currently supported by any code in this
101 /// component).
102 ///
103 /// # Arguments
104 ///
105 /// - `params` - the OAuth parameters from the incoming authorization request
106 #[handle_error(Error)]
107 pub fn authorize_code_using_session_token(
108 &self,
109 params: AuthorizationParameters,
110 ) -> ApiResult<String> {
111 self.internal
112 .lock()
113 .authorize_code_using_session_token(params)
114 }
115
116 /// Clear the access token cache in response to an auth failure.
117 ///
118 /// **💾 This method alters the persisted account state.**
119 ///
120 /// Applications that receive an authentication error when trying to use an access token,
121 /// should call this method before creating a new token and retrying the failed operation.
122 /// It ensures that the expired token is removed and a fresh one generated.
123 pub fn clear_access_token_cache(&self) {
124 self.internal.lock().clear_access_token_cache()
125 }
126}
127
128/// An OAuth access token, with its associated keys and metadata.
129///
130/// This struct represents an FxA OAuth access token, which can be used to access a resource
131/// or service on behalf of the user. For example, accessing the user's data in Firefox Sync
132/// an access token for the scope `https://identity.mozilla.com/apps/sync` along with the
133/// associated encryption key.
134#[derive(Debug)]
135pub struct AccessTokenInfo {
136 /// The scope of access granted by token.
137 pub scope: String,
138 /// The access token itself.
139 ///
140 /// This is the value that should be included in the `Authorization` header when
141 /// accessing an OAuth protected resource on behalf of the user.
142 pub token: String,
143 /// The client-side encryption key associated with this scope.
144 ///
145 /// **⚠️ Warning:** the value of this field should never be revealed outside of the
146 /// application. For example, it should never to sent to a server or logged in a log file.
147 pub key: Option<ScopedKey>,
148 /// The expiry time of the token, in seconds.
149 ///
150 /// This is the timestamp at which the token is set to expire, in seconds since
151 /// unix epoch. Note that it is a signed integer, for compatibility with languages
152 /// that do not have an unsigned integer type.
153 ///
154 /// This timestamp is for guidance only. Access tokens are not guaranteed to remain
155 /// value for any particular lengthof time, and consumers should be prepared to handle
156 /// auth failures even if the token has not yet expired.
157 pub expires_at: i64,
158}
159
160/// A cryptographic key associated with an OAuth scope.
161///
162/// Some OAuth scopes have a corresponding client-side encryption key that is required
163/// in order to access protected data. This struct represents such key material in a
164/// format compatible with the common "JWK" standard.
165///
166#[derive(Clone, Serialize, Deserialize)]
167pub struct ScopedKey {
168 /// The type of key.
169 ///
170 /// In practice for FxA, this will always be string string "oct" (short for "octal")
171 /// to represent a raw symmetric key.
172 pub kty: String,
173 /// The OAuth scope with which this key is associated.
174 pub scope: String,
175 /// The key material, as base64-url-encoded bytes.
176 ///
177 /// **⚠️ Warning:** the value of this field should never be revealed outside of the
178 /// application. For example, it should never to sent to a server or logged in a log file.
179 pub k: String,
180 /// An opaque unique identifier for this key.
181 ///
182 /// Unlike the `k` field, this value is not secret and may be revealed to the server.
183 pub kid: String,
184}
185
186/// Parameters provided in an incoming OAuth request.
187///
188/// This struct represents parameters obtained from an incoming OAuth request - that is,
189/// the values that an OAuth client would append to the authorization URL when initiating
190/// an OAuth sign-in flow.
191pub struct AuthorizationParameters {
192 pub client_id: String,
193 pub scope: Vec<String>,
194 pub state: String,
195 pub access_type: String,
196 pub code_challenge: Option<String>,
197 pub code_challenge_method: Option<String>,
198 pub keys_jwk: Option<String>,
199}