31 lines
1.2 KiB
Dart
31 lines
1.2 KiB
Dart
import 'dart:convert';
|
|
import 'dart:math';
|
|
|
|
import 'package:crypto/crypto.dart';
|
|
|
|
/// PKCE (RFC 7636) verifier/challenge pair for Dropbox's and OneDrive's
|
|
/// OAuth2 Authorization Code flow — proves to the token endpoint that the
|
|
/// app completing the exchange is the same one that started the browser
|
|
/// redirect, without needing an embedded client secret (appropriate for a
|
|
/// public/mobile client, since a secret can't actually be kept secret in
|
|
/// a distributed app binary).
|
|
class PkcePair {
|
|
final String codeVerifier;
|
|
final String codeChallenge;
|
|
|
|
PkcePair._(this.codeVerifier, this.codeChallenge);
|
|
|
|
factory PkcePair.generate() {
|
|
final verifier = _randomUrlSafeString(64);
|
|
final challenge =
|
|
base64Url.encode(sha256.convert(utf8.encode(verifier)).bytes).replaceAll('=', '');
|
|
return PkcePair._(verifier, challenge);
|
|
}
|
|
|
|
static String _randomUrlSafeString(int length) {
|
|
// RFC 7636's unreserved character set for a code_verifier.
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
|
|
final random = Random.secure();
|
|
return List.generate(length, (_) => chars[random.nextInt(chars.length)]).join();
|
|
}
|
|
}
|