add pkce class
This commit is contained in:
parent
d1213e779a
commit
71611f7f6a
5 changed files with 76 additions and 4 deletions
|
@ -11,7 +11,7 @@ In your `pubspec.yaml`:
|
|||
|
||||
```yaml
|
||||
dependencies:
|
||||
angel_oauth2: ^1.0.0
|
||||
angel_oauth2: ^2.0.0
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
@ -49,7 +49,7 @@ class _Server extends AuthorizationServer<PseudoApplication, Map> {
|
|||
```
|
||||
|
||||
Next, write some logic to be executed whenever a user visits the
|
||||
authorization endpoint. In most cases, you will want to show a dialog:
|
||||
authorization endpoint. In many cases, you will want to show a dialog:
|
||||
|
||||
```dart
|
||||
@override
|
||||
|
@ -99,7 +99,7 @@ The following are available, not including authorization code grant support (men
|
|||
* `implicitGrant`
|
||||
* `resourceOwnerPasswordCredentialsGrant`
|
||||
* `clientCredentialsGrant`
|
||||
* `deviceCode`
|
||||
* `deviceCodeGrant`
|
||||
|
||||
Read the [OAuth2 specification](https://tools.ietf.org/html/rfc6749)
|
||||
for in-depth information on each grant type.
|
|
@ -1,4 +1,5 @@
|
|||
export 'src/exception.dart';
|
||||
export 'src/pkce.dart';
|
||||
export 'src/response.dart';
|
||||
export 'src/server.dart';
|
||||
export 'src/token_type.dart';
|
||||
export 'src/token_type.dart';
|
|
@ -28,6 +28,9 @@ class ErrorResponse {
|
|||
/// The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.
|
||||
static const String invalidRequest = 'invalid_request';
|
||||
|
||||
/// The `code_verifier` given by the client does not match the expected value.
|
||||
static const String invalidGrant = 'invalid_grant';
|
||||
|
||||
/// The client is not authorized to request an authorization code using this method.
|
||||
static const String unauthorizedClient = 'unauthorized_client';
|
||||
|
||||
|
|
67
lib/src/pkce.dart
Normal file
67
lib/src/pkce.dart
Normal file
|
@ -0,0 +1,67 @@
|
|||
import 'dart:convert';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'exception.dart';
|
||||
|
||||
/// A class that facilitates verification of challenges for
|
||||
/// [Proof Key for Code Exchange](https://oauth.net/2/pkce/).
|
||||
class Pkce {
|
||||
/// A [String] defining how to handle the [codeChallenge].
|
||||
final String codeChallengeMethod;
|
||||
|
||||
/// The proof key that is used to secure public clients.
|
||||
final String codeChallenge;
|
||||
|
||||
Pkce(this.codeChallengeMethod, this.codeChallenge) {
|
||||
assert(codeChallengeMethod == 'plain' || codeChallengeMethod == 's256',
|
||||
"The `code_challenge_method` parameter must be either 'plain' or 's256'.");
|
||||
}
|
||||
|
||||
/// Attempts to parse a [codeChallenge] and [codeChallengeMethod] from a [Map].
|
||||
factory Pkce.fromJson(Map data, {String state, Uri uri}) {
|
||||
var codeChallenge = data['code_challenge']?.toString();
|
||||
var codeChallengeMethod =
|
||||
data['code_challenge_method']?.toString() ?? 'plain';
|
||||
|
||||
if (codeChallengeMethod != 'plain' && codeChallengeMethod != 's256') {
|
||||
throw new AuthorizationException(new ErrorResponse(
|
||||
ErrorResponse.invalidRequest,
|
||||
"The `code_challenge_method` parameter must be either 'plain' or 's256'.",
|
||||
state,
|
||||
uri: uri));
|
||||
} else if (codeChallenge?.isNotEmpty != true) {
|
||||
throw new AuthorizationException(new ErrorResponse(
|
||||
ErrorResponse.invalidRequest,
|
||||
'Missing `code_challenge` parameter.',
|
||||
state,
|
||||
uri: uri));
|
||||
}
|
||||
|
||||
return new Pkce(codeChallengeMethod, codeChallenge);
|
||||
}
|
||||
|
||||
/// Returns [true] if the [codeChallengeMethod] is `plain`.
|
||||
bool get isPlain => codeChallengeMethod == 'plain';
|
||||
|
||||
/// Returns [true] if the [codeChallengeMethod] is `s256`.
|
||||
bool get isS256 => codeChallengeMethod == 's256';
|
||||
|
||||
/// Determines if a given [codeVerifier] is valid.
|
||||
void validate(String codeVerifier, {String state, Uri uri}) {
|
||||
String foreignChallenge;
|
||||
|
||||
if (isS256) {
|
||||
foreignChallenge =
|
||||
base64Url.encode(sha256.convert(ascii.encode(codeChallenge)).bytes);
|
||||
} else {
|
||||
foreignChallenge = codeChallenge;
|
||||
}
|
||||
|
||||
if (foreignChallenge != codeChallenge) {
|
||||
throw new AuthorizationException(
|
||||
new ErrorResponse(ErrorResponse.invalidGrant,
|
||||
"The given `code_verifier` parameter is invalid.", state,
|
||||
uri: uri),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'exception.dart';
|
||||
import 'pkce.dart';
|
||||
import 'response.dart';
|
||||
import 'token_type.dart';
|
||||
|
||||
|
|
Loading…
Reference in a new issue