blob: 39b90f2f2bf5594f8bbfbfc14cfb56c479559809 [file]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../access_credentials.dart';
import '../crypto/rsa.dart';
import '../crypto/rsa_sign.dart';
import '../known_uris.dart';
import '../utils.dart';
import 'base_flow.dart';
class JwtFlow extends BaseFlow {
// All details are described at:
// https://developers.google.com/accounts/docs/OAuth2ServiceAccount
// JSON Web Signature (JWS) requires signing a string with a private key.
final String _clientEmail;
final RS256Signer _signer;
final List<String> _scopes;
final String? _user;
final http.Client _client;
JwtFlow(
this._clientEmail,
RSAPrivateKey key,
this._user,
this._scopes,
this._client,
) : _signer = RS256Signer(key);
@override
Future<AccessCredentials> run() async {
final timestamp = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000 -
maxExpectedTimeDiffInSeconds;
final jwtHeader = {'alg': 'RS256', 'typ': 'JWT'};
final jwtHeaderBase64 = _base64url(ascii.encode(jsonEncode(jwtHeader)));
final jwtClaimSet = {
'iss': _clientEmail,
'scope': _scopes.join(' '),
'aud': googleOauth2TokenEndpoint.toString(),
'exp': timestamp + 3600,
'iat': timestamp,
if (_user != null) 'sub': _user!,
};
final jwtClaimSetBase64 = _base64url(utf8.encode(jsonEncode(jwtClaimSet)));
final jwtSignatureInput = '$jwtHeaderBase64.$jwtClaimSetBase64';
final jwtSignatureInputInBytes = ascii.encode(jwtSignatureInput);
final signature = _signer.sign(jwtSignatureInputInBytes);
final jwt = '$jwtSignatureInput.${_base64url(signature)}';
// https://developers.google.com/identity/protocols/oauth2/service-account#authorizingrequests
final response = await _client.oauthTokenRequest({
'grant_type': _uri,
'assertion': jwt,
});
final accessToken = parseAccessToken(response);
return AccessCredentials(accessToken, null, _scopes);
}
}
const _uri = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
String _base64url(List<int> bytes) =>
base64Url.encode(bytes).replaceAll('=', '');