From b01578d4b978380a7cfdf3eea75a0ca48896adbf Mon Sep 17 00:00:00 2001 From: Muhammad Qasim Date: Sat, 25 Jun 2022 12:34:02 +0500 Subject: [PATCH] Added customParams in authorizeUI for Implicit grant flow --- lib/oauth2_client.dart | 103 ++++++++++++----------------------------- lib/oauth2_helper.dart | 72 +++++++++------------------- 2 files changed, 50 insertions(+), 125 deletions(-) diff --git a/lib/oauth2_client.dart b/lib/oauth2_client.dart index a8b25a8..898d03a 100644 --- a/lib/oauth2_client.dart +++ b/lib/oauth2_client.dart @@ -81,7 +81,8 @@ class OAuth2Client { String? state, httpClient, BaseWebAuth? webAuthClient, - Map? webAuthOpts}) async { + Map? webAuthOpts, + Map? customParams}) async { httpClient ??= http.Client(); webAuthClient ??= this.webAuthClient; @@ -93,22 +94,19 @@ class OAuth2Client { scopes: scopes, enableState: enableState, state: state, - redirectUri: redirectUri); + redirectUri: redirectUri, + customParams: customParams); // Present the dialog to the user final result = await webAuthClient.authenticate( - url: authorizeUrl, - callbackUrlScheme: customUriScheme, - redirectUrl: redirectUri, - opts: webAuthOpts); + url: authorizeUrl, callbackUrlScheme: customUriScheme, redirectUrl: redirectUri, opts: webAuthOpts); final fragment = Uri.splitQueryString(Uri.parse(result).fragment); if (enableState) { final checkState = fragment['state']; if (state != checkState) { - throw Exception( - '"state" parameter in response doesn\'t correspond to the expected value'); + throw Exception('"state" parameter in response doesn\'t correspond to the expected value'); } } @@ -178,10 +176,7 @@ class OAuth2Client { /// Requests an Access Token to the OAuth2 endpoint using the Client Credentials flow. Future getTokenWithClientCredentialsFlow( - {required String clientId, - required String clientSecret, - List? scopes, - httpClient}) async { + {required String clientId, required String clientSecret, List? scopes, httpClient}) async { var params = {'grant_type': 'client_credentials'}; if (scopes != null && scopes.isNotEmpty) { @@ -189,11 +184,7 @@ class OAuth2Client { } var response = await _performAuthorizedRequest( - url: tokenUrl, - clientId: clientId, - clientSecret: clientSecret, - params: params, - httpClient: httpClient); + url: tokenUrl, clientId: clientId, clientSecret: clientSecret, params: params, httpClient: httpClient); return http2TokenResponse(response, requestedScopes: scopes); } @@ -225,10 +216,7 @@ class OAuth2Client { // Present the dialog to the user final result = await webAuthClient.authenticate( - url: authorizeUrl, - callbackUrlScheme: customUriScheme, - redirectUrl: redirectUri, - opts: webAuthOpts); + url: authorizeUrl, callbackUrlScheme: customUriScheme, redirectUrl: redirectUri, opts: webAuthOpts); return AuthorizationResponse.fromRedirectUri(result, state); } @@ -242,11 +230,8 @@ class OAuth2Client { List? scopes, Map? customParams, httpClient}) async { - final params = getTokenUrlParams( - code: code, - redirectUri: redirectUri, - codeVerifier: codeVerifier, - customParams: customParams); + final params = + getTokenUrlParams(code: code, redirectUri: redirectUri, codeVerifier: codeVerifier, customParams: customParams); var response = await _performAuthorizedRequest( url: tokenUrl, @@ -261,18 +246,11 @@ class OAuth2Client { /// Refreshes an Access Token issuing a refresh_token grant to the OAuth2 server. Future refreshToken(String refreshToken, - {httpClient, - required String clientId, - String? clientSecret, - List? scopes}) async { + {httpClient, required String clientId, String? clientSecret, List? scopes}) async { final Map params = getRefreshUrlParams(refreshToken: refreshToken); var response = await _performAuthorizedRequest( - url: _getRefreshUrl(), - clientId: clientId, - clientSecret: clientSecret, - params: params, - httpClient: httpClient); + url: _getRefreshUrl(), clientId: clientId, clientSecret: clientSecret, params: params, httpClient: httpClient); return http2TokenResponse(response, requestedScopes: scopes); } @@ -280,13 +258,11 @@ class OAuth2Client { /// Revokes both the Access and the Refresh tokens in the provided [tknResp] Future revokeToken(AccessTokenResponse tknResp, {String? clientId, String? clientSecret, httpClient}) async { - var tokenRevocationResp = await revokeAccessToken(tknResp, - clientId: clientId, clientSecret: clientSecret, httpClient: httpClient); + var tokenRevocationResp = + await revokeAccessToken(tknResp, clientId: clientId, clientSecret: clientSecret, httpClient: httpClient); if (tokenRevocationResp.isValid()) { - tokenRevocationResp = await revokeRefreshToken(tknResp, - clientId: clientId, - clientSecret: clientSecret, - httpClient: httpClient); + tokenRevocationResp = + await revokeRefreshToken(tknResp, clientId: clientId, clientSecret: clientSecret, httpClient: httpClient); } return tokenRevocationResp; @@ -316,10 +292,7 @@ class OAuth2Client { String? state, String? codeChallenge, Map? customParams}) { - final params = { - 'response_type': responseType, - 'client_id': clientId - }; + final params = {'response_type': responseType, 'client_id': clientId}; if (redirectUri != null && redirectUri.isNotEmpty) { params['redirect_uri'] = redirectUri; @@ -347,14 +320,8 @@ class OAuth2Client { /// Returns the parameters needed for the authorization code request Map getTokenUrlParams( - {required String code, - String? redirectUri, - String? codeVerifier, - Map? customParams}) { - final params = { - 'grant_type': 'authorization_code', - 'code': code - }; + {required String code, String? redirectUri, String? codeVerifier, Map? customParams}) { + final params = {'grant_type': 'authorization_code', 'code': code}; if (redirectUri != null && redirectUri.isNotEmpty) { params['redirect_uri'] = redirectUri; @@ -414,19 +381,16 @@ class OAuth2Client { } } - var response = - await httpClient.post(Uri.parse(url), body: params, headers: headers); + var response = await httpClient.post(Uri.parse(url), body: params, headers: headers); return response; } - Map getAuthorizationHeader( - {required String clientId, String? clientSecret}) { + Map getAuthorizationHeader({required String clientId, String? clientSecret}) { var headers = {}; if ((clientId.isNotEmpty) && (clientSecret != null)) { - var credentials = - base64.encode(utf8.encode(clientId + ':' + clientSecret)); + var credentials = base64.encode(utf8.encode(clientId + ':' + clientSecret)); headers['Authorization'] = 'Basic ' + credentials; } @@ -436,18 +400,13 @@ class OAuth2Client { /// Returns the parameters needed for the refresh token request Map getRefreshUrlParams({required String refreshToken}) { - final params = { - 'grant_type': 'refresh_token', - 'refresh_token': refreshToken - }; + final params = {'grant_type': 'refresh_token', 'refresh_token': refreshToken}; return params; } - AccessTokenResponse http2TokenResponse(http.Response response, - {List? requestedScopes}) { - return AccessTokenResponse.fromHttpResponse(response, - requestedScopes: requestedScopes); + AccessTokenResponse http2TokenResponse(http.Response response, {List? requestedScopes}) { + return AccessTokenResponse.fromHttpResponse(response, requestedScopes: requestedScopes); } String serializeScopes(List scopes) { @@ -455,8 +414,7 @@ class OAuth2Client { } /// Revokes the specified token [type] in the [tknResp] - Future _revokeTokenByType( - AccessTokenResponse tknResp, String tokenType, + Future _revokeTokenByType(AccessTokenResponse tknResp, String tokenType, {String? clientId, String? clientSecret, httpClient}) async { var resp = OAuth2Response(); @@ -464,9 +422,7 @@ class OAuth2Client { httpClient ??= http.Client(); - var token = tokenType == 'access_token' - ? tknResp.accessToken - : tknResp.refreshToken; + var token = tokenType == 'access_token' ? tknResp.accessToken : tknResp.refreshToken; if (token != null) { var params = {'token': token, 'token_type_hint': tokenType}; @@ -474,8 +430,7 @@ class OAuth2Client { if (clientId != null) params['client_id'] = clientId; if (clientSecret != null) params['client_secret'] = clientSecret; - http.Response response = - await httpClient.post(Uri.parse(revokeUrl!), body: params); + http.Response response = await httpClient.post(Uri.parse(revokeUrl!), body: params); resp = http2TokenResponse(response); } diff --git a/lib/oauth2_helper.dart b/lib/oauth2_helper.dart index 25c6282..a45ca95 100644 --- a/lib/oauth2_helper.dart +++ b/lib/oauth2_helper.dart @@ -100,8 +100,7 @@ class OAuth2Helper { } if (!tknResp.isValid()) { - throw Exception( - 'Provider error ${tknResp.httpStatusCode}: ${tknResp.error}: ${tknResp.errorDescription}'); + throw Exception('Provider error ${tknResp.httpStatusCode}: ${tknResp.error}: ${tknResp.errorDescription}'); } if (!tknResp.isBearer()) { @@ -146,7 +145,8 @@ class OAuth2Helper { scopes: scopes, enableState: enableState, webAuthClient: webAuthClient, - webAuthOpts: webAuthOpts); + webAuthOpts: webAuthOpts, + customParams: authCodeParams); } else { tknResp = AccessTokenResponse.errorResponse(); } @@ -159,15 +159,12 @@ class OAuth2Helper { } /// Performs a refresh_token request using the [refreshToken]. - Future refreshToken( - AccessTokenResponse curTknResp) async { + Future refreshToken(AccessTokenResponse curTknResp) async { var tknResp; var refreshToken = curTknResp.refreshToken!; try { tknResp = await client.refreshToken(refreshToken, - clientId: clientId, - clientSecret: clientSecret, - scopes: curTknResp.scope); + clientId: clientId, clientSecret: clientSecret, scopes: curTknResp.scope); } catch (_) { return await fetchToken(); } @@ -188,8 +185,7 @@ class OAuth2Helper { //Fetch another access token tknResp = await getToken(); } else { - throw OAuth2Exception(tknResp.error, - errorDescription: tknResp.errorDescription); + throw OAuth2Exception(tknResp.error, errorDescription: tknResp.errorDescription); } } @@ -204,10 +200,7 @@ class OAuth2Helper { if (tknResp != null) { await tokenStorage.deleteToken(scopes ?? []); - return await client.revokeToken(tknResp, - clientId: clientId, - clientSecret: clientSecret, - httpClient: httpClient); + return await client.revokeToken(tknResp, clientId: clientId, clientSecret: clientSecret, httpClient: httpClient); } else { return OAuth2Response(); } @@ -220,68 +213,49 @@ class OAuth2Helper { /// Performs a POST request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future post(String url, - {Map? headers, - dynamic body, - http.Client? httpClient}) async { - return _request('POST', url, - headers: headers, body: body, httpClient: httpClient); + Future post(String url, {Map? headers, dynamic body, http.Client? httpClient}) async { + return _request('POST', url, headers: headers, body: body, httpClient: httpClient); } /// Performs a PUT request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future put(String url, - {Map? headers, - dynamic body, - http.Client? httpClient}) async { - return _request('PUT', url, - headers: headers, body: body, httpClient: httpClient); + Future put(String url, {Map? headers, dynamic body, http.Client? httpClient}) async { + return _request('PUT', url, headers: headers, body: body, httpClient: httpClient); } /// Performs a PATCH request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future patch(String url, - {Map? headers, - dynamic body, - http.Client? httpClient}) async { - return _request('PATCH', url, - headers: headers, body: body, httpClient: httpClient); + Future patch(String url, {Map? headers, dynamic body, http.Client? httpClient}) async { + return _request('PATCH', url, headers: headers, body: body, httpClient: httpClient); } /// Performs a GET request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future get(String url, - {Map? headers, http.Client? httpClient}) async { + Future get(String url, {Map? headers, http.Client? httpClient}) async { return _request('GET', url, headers: headers, httpClient: httpClient); } /// Performs a DELETE request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future delete(String url, - {Map? headers, http.Client? httpClient}) async { + Future delete(String url, {Map? headers, http.Client? httpClient}) async { return _request('DELETE', url, headers: headers, httpClient: httpClient); } /// Performs a HEAD request to the specified [url], adding the authorization token. /// /// If no token already exists, or if it is expired, a new one is requested. - Future head(String url, - {Map? headers, - dynamic body, - http.Client? httpClient}) async { + Future head(String url, {Map? headers, dynamic body, http.Client? httpClient}) async { return _request('HEAD', url, headers: headers, httpClient: httpClient); } /// Common method for making http requests /// Tries to use a previously fetched token, otherwise fetches a new token by means of a refresh flow or by issuing a new authorization flow Future _request(String method, String url, - {Map? headers, - dynamic body, - http.Client? httpClient}) async { + {Map? headers, dynamic body, http.Client? httpClient}) async { httpClient ??= http.Client(); headers ??= {}; @@ -292,14 +266,11 @@ class OAuth2Helper { headers!['Authorization'] = 'Bearer ' + accessToken; if (method == 'POST') { - resp = await httpClient! - .post(Uri.parse(url), body: body, headers: headers); + resp = await httpClient!.post(Uri.parse(url), body: body, headers: headers); } else if (method == 'PUT') { - resp = - await httpClient!.put(Uri.parse(url), body: body, headers: headers); + resp = await httpClient!.put(Uri.parse(url), body: body, headers: headers); } else if (method == 'PATCH') { - resp = await httpClient! - .patch(Uri.parse(url), body: body, headers: headers); + resp = await httpClient!.patch(Uri.parse(url), body: body, headers: headers); } else if (method == 'GET') { resp = await httpClient!.get(Uri.parse(url), headers: headers); } else if (method == 'DELETE') { @@ -343,8 +314,7 @@ class OAuth2Helper { throw Exception('Required "clientId" parameter not set'); } - if (grantType == CLIENT_CREDENTIALS && - (clientSecret == null || clientSecret!.isEmpty)) { + if (grantType == CLIENT_CREDENTIALS && (clientSecret == null || clientSecret!.isEmpty)) { throw Exception('Required "clientSecret" parameter not set'); } }