From 0ae5f7d30ca38764fe168716e6ad875b35e23725 Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Tue, 20 Jun 2017 11:08:27 +0100 Subject: [PATCH 01/11] Initial edit --- README.md | 237 ++++++++++++++++++++++++------------------------------ 1 file changed, 105 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index f619876..f2470a8 100644 --- a/README.md +++ b/README.md @@ -14,38 +14,32 @@ operations including refresh token management and expired access token renewal. ## OAuth2.JWTProfile.Client -The class implements OAuth 2.0 flow with JSON Web Token (JWT) Bearer Token as a means for requesting -an access token as well as for client authentication. +The class implements OAuth 2.0 flow using JSON Web Token (JWT) Bearer Token as a means for requesting an access token and for client authentication. -**NOTE:** The flow requires RSA SHA256 signature, which is not currently supported by the Electric Imp -[Agent API](https://electricimp.com/docs/api/agent/). As a temporary solution it is proposed to use -[AWS Lambda](https://aws.amazon.com/lambda) function that will do -[RSA-SHA256 signatures](examples#amazon-lambda-for-rsa-sha256-signatures) for an agent. -AWS Lambda is subject to a service charge (please refer to Amazon pricing -[page](https://aws.amazon.com/lambda/pricing/) for more details). +**Note** The flow requires RSA-SHA256 signature, which is not currently supported by the Electric Imp [imp API](https://electricimp.com/docs/api/). As a temporary solution we suggest that you use an [AWS Lambda](https://aws.amazon.com/lambda) function that will do [RSA-SHA256 signatures](examples#amazon-lambda-for-rsa-sha256-signatures) for an agent. AWS Lambda is subject to a service charge so please refer to the Amazon pricing +[page](https://aws.amazon.com/lambda/pricing/) for more information. -### constructor(providerSettings, userSettings) +## OAuth2.JWTProfile.Client Usage -Construction that creates an instance of the `OAuth2.JWTProfile.Client`. +### constructor(*providerSettings, userSettings*) -The first parameter `providerSettings` is a map that contains provider specific settings: +The constructor creates an instance of an *OAuth2.JWTProfile.Client* object. The first parameter, *providerSettings*, is a map that contains provider-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| `TOKEN_HOST` | *string* | Required | Token endpoint - used by the client to exchange an authorization grant for an access token, typically with client authentication. | +| *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | -The second parameter `userSettings` defines a map with user and application specific settings: +The second parameter, *userSettings*, defines a map with user- and application-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| `iss` | *string* | Required | JWT issuer | -| `scope` | *string* | Required | Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application | -| `jwtSignKey` | *string* | Required | JWT sign secret key | -| `rs256signer` | *[AWSLambda](https://github.com/electricimp/awslambda)* | Required | Instance of [AWSLambda](https://github.com/electricimp/awslambda) for RSA-SHA256 encryption. You can use [example](examples#jwt-profile-for-oauth-20) code to create the AWS Lambda function. | -| `sub` | *string* | Optional. *Default:* the value of `iss` | The *subject* of the JWT. Google seems to ignor this field. | - -*Note* Optional `sub` property is substituted by mandatory `iss` property when omitted. +| *iss* | String | Required | The JSON Web Token issuer | +| *scope* | String | Required | Scopes enable your application to request access only to the resources that it needs while also enabling users to control the amount of access that they grant to your application | +| *jwtSignKey* | String | Required | A JWT sign secret key | +| *rs256signer* | *[AWSLambda](https://github.com/electricimp/awslambda)* | Required | Instance of [AWSLambda](https://github.com/electricimp/awslambda) for RSA-SHA256 encryption. You can use [this example code](examples#jwt-profile-for-oauth-20) to create the AWS Lambda function | +| *sub* | String | Optional. *Default:* the value of `iss` | The *subject* of the JWT. Google seems to ignor this field. | +**Note** When omitted, the optional *sub* property is substituted by the mandatory *iss* property. #### JWT Profile Client Creation Example @@ -70,6 +64,7 @@ local signer = AWSLambda(LAMBDA_REGION, LAMBDA_ACCESS_KEY_ID, LAMBDA_ACCESS_KEY) local providerSettings = { "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token" }; + local userSettings = { "iss" : GOOGLE_ISS, "jwtSignKey" : GOOGLE_SECRET_KEY, @@ -79,70 +74,64 @@ local userSettings = { local client = OAuth2.JWTProfile.Client(providerSettings, userSettings); ``` -**IMPORTANT:** The name of the AWS Lambda function must be `RSALambda`! +**Important** The name of the AWS Lambda function **must** be `RSALambda`. -### acquireAccessToken(tokenReadyCallback) +## OAuth2.JWTProfile.Client Methods -Starts access token acquisition procedure. Invokes the provided callback function immediately -if access token is available and valid. +### acquireAccessToken(*tokenReadyCallback*) -Parameter details: +This method begins the access-token acquisition procedure. It invokes the provided callback function immediately if the access token is available and valid. -| Parameter | Type | Use | Description | -| --- | --- | --- | --- | -| `tokenReadyCallback` | Function | Required | The handler to be called when access token is acquired or an error occurs | - -`tokenReadyCallback` callback should have two parameters: +The function passed into *tokenReadyCallback* should have two parameters if its own: | Parameter | Type | Description | | --- | --- | --- | -| `token` | *string* | String representation of access token | -| `error` | *string* | String with error details, `null` in case of success | +| *token* | String | String representation of the access token | +| *error* | String | String with error details, otherwise `null` in the case of success | #### Example -Using `client` from previous [sample](#jwt-profile-client-creation-example) +Using *client* from the [construction example](#jwt-profile-client-creation-example): ```squirrel client.acquireAccessToken( function(resp, err) { - server.log(resp); if (err) { server.error(err); + } else { + server.log("Access Token: " + resp); } } ); ``` + ### getValidAccessTokeOrNull() -Returns access token string non blocking way. Returns access token as a string object if token is valid, -null if the client is not authorized or token is expired. +This method returns an access token string in a non-blocking way. It returns the access token as a string if the token is valid, or `null` if the client is not authorized or the token has expired. #### Example -Using `client` from the first [sample](#jwt-profile-client-creation-example) - ```squirrel local token = client.getValidAccessTokeOrNull(); -if (token) server.log("token is valid and has value: " + token); -else server.log("token is either expired or client is not authorized!"); + +if (token) { + server.log("token is valid and has value: " + token); +} else { + server.log("token is either expired or client is not authorized!"); +} ``` ### isTokenValid() -Checks if access token is valid by comparing its expire time with current one. +This method checks if the access token is valid by comparing its expiry time with current time. It returns a Boolean value: `true` if the token is valid, or `false` if the token has expired. #### Example -Using `client` from the first [sample](#jwt-profile-client-creation-example) - ```squirrel -server.log("token is valid=" + client.isTokenValid()); +server.log("The access token is " + (client.isTokenValid() ? "valid" : "invalid")); ``` -## Complete usage sample - -To connect all the parts together and show a sample of common case of library usage let's take a look a following sample +## Complete Example ```squirrel #require "AWSRequestV4.class.nut:1.0.2" @@ -161,6 +150,7 @@ local signer = AWSLambda(LAMBDA_REGION, LAMBDA_ACCESS_KEY_ID, LAMBDA_ACCESS_KEY) local providerSettings = { "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token" }; + local userSettings = { "iss" : GOOGLE_ISS, "jwtSignKey" : GOOGLE_SECRET_KEY, @@ -185,107 +175,97 @@ if (token != null) { } ); - if (null != error) server.error("Failed to obtain token: " + error); + if (error != null) server.error("Failed to obtain token: " + error); } ``` -**NOTE:** JWT Profile for OAuth 2.0 was verified and tested with -Google [PubSub](https://cloud.google.com/pubsub/docs/) authorization flow. - +**Note** The JSON Web Token (JWT) Profile for OAuth 2.0 was verified and tested with the Google [PubSub](https://cloud.google.com/pubsub/docs/) authorization flow. ## OAuth2.DeviceFlow.Client -The class implements OAuth 2.0 authorization flow for browserless and input -constrained devices, often referred to as the -[device flow](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05), enables -OAuth clients to request user authorization from devices that have an -Internet connection, but don't have an easy input method, or lack a -suitable browser for a more traditional OAuth flow. This -authorization flow instructs the user to perform the authorization -request on a secondary device, such as a smartphone. +This class implements an OAuth 2.0 authorization flow for browserless and/or input-constrained devices. Often referred to as the [device flow](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05), this flow enables OAuth clients to request user authorization from devices that have an Internet connection, but lack a suitable input method or web browser for a more traditional OAuth flow. This authorization flow therefore instructs the user to perform the authorization request on a secondary device, such as a smartphone. +## OAuth2.DeviceFlow.Client Usage -### constructor(providerSettings, userSettings) +### constructor(*providerSettings, userSettings*) -Construction that creates an instance of the `OAuth2.DeviceFlow.Client`. - -The first parameter `providerSettings` is a map that contains provider specific settings: +This constructor creates an instance of the *OAuth2.DeviceFlow.Client* class. The first parameter, *providerSettings*, is a map that contains provider-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| `LOGIN_HOST` | *string* | Required | Authorization endpoint - used by the client to obtain authorization from the resource owner via user-agent redirection. authorization server | -| `TOKEN_HOST` | *string* | Required | Token endpoint - used by the client to exchange an authorization grant for an access token, typically with client authentication. | -| `GRANT_TYPE` | *string* | Optional. *Default:* `urn:ietf:params:oauth:grant-type:device_code` | Grant type identifier supported by the provider | +| *LOGIN_HOST* | String | Required | The authorization endpoint. This is used by the client to obtain authorization from the resource owner via user-agent redirection | +| *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | +| *GRANT_TYPE* | String | Optional. Default: `"urn:ietf:params:oauth:grant-type:device_code"` | The grant type identifier supported by the provider | -The second parameter `userSettings` defines a map with user and application specific settings: +The second parameter, *userSettings*, defines a map with user- and application-specific settings: | Parameter | Type | Use |Description | | --- | --- | --- | --- | -| `clientId` | *string* | Required | OAuth client ID | -| `clientSecret` | *string* | Required | The project's client secret | -| `scope` | *string* | Required | Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application. | +| *clientId* | String | Required | The OAuth client ID | +| *clientSecret* | String | Required | The project's client secret | +| *scope* | String | Required | A scope. Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application | -The library provides predefined configuration settings for -Google Device Auth flow. These settings are defined in the provider -specific settings map:`OAuth2.DeviceFlow.GOOGLE`. The table -provides `LOGIN_HOST`, `TOKEN_HOST` and `GRANT_TYPE` values. +The library provides predefined configuration settings for the Google Device Auth flow. These settings are defined in the provider-specific settings map: *OAuth2.DeviceFlow.GOOGLE*. This table provides pre-populated *LOGIN_HOST, TOKEN_HOST* and *GRANT_TYPE* values. #### Device Flow Client Creation Example ```squirrel - local providerSettings = { - "LOGIN_HOST" : "https://accounts.google.com/o/oauth2/device/code", - "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token", - "GRANT_TYPE" : "http://oauth.net/grant_type/device/1.0", - }; - local userSettings = { - "clientId" : "USER_FIREBASE_CLIENT_ID", - "clientSecret" : "USER_FIREBASE_CLIENT_SECRET", - "scope" : "email profile", - }; - - client <- OAuth2.DeviceFlow.Client(providerSettings, userSettings); +local providerSettings = { + "LOGIN_HOST" : "https://accounts.google.com/o/oauth2/device/code", + "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token", + "GRANT_TYPE" : "http://oauth.net/grant_type/device/1.0", +}; + +local userSettings = { + "clientId" : "", + "clientSecret" : "", + "scope" : "email profile", +}; + +client <- OAuth2.DeviceFlow.Client(providerSettings, userSettings); ``` -### acquireAccessToken(tokenReadyCallback, notifyUserCallback, force) +## OAuth2.DeviceFlow.Client Methods + +### acquireAccessToken(*tokenReadyCallback, notifyUserCallback, force*) -Starts access token acquisition procedure. Depending on Client state may starts full client authorization procedure or -just token refreshing. Returns null in case of success and error otherwise. Access token is delivered through provided *tokenReadyCallback* function. +This methiod begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message otherwise. The access token is delivered through the function passed into the *tokenReadyCallback* function. Parameter details: | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| `tokenReadyCallback` | *function* | Required | The handler to be called when access token is acquired or an error occurred | -| `notifyUserCallback` | *function* | Required | The handler to be called when user action is required. See [RFE, device flow, section3.3](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05#section-3.3) | -| `force` | *boolean* | Optional. *Default:* `false` | The flag forces the token acquisition process to start from the beginning even if the previous request did not complete yet. The previous session will be terminated. | +| *tokenReadyCallback* | Function | Required | The handler that will be called when the access token has been acquired, or an error has occurred. The function’s parameters are described below | +| *notifyUserCallback* | Function | Required | The handler that will be called when user action is required. See [RFE, device flow, section 3.3](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05#section-3.3) for information on what user action might be needed when this callback is executed. The function’s parameters are described below | +| *force* | Boolean | Optional. Default: `false` | This flag forces the token acquisition process to start from the beginning even if a previous request has not yet completed. Any previous session will be terminated | -where `tokenReadyCallback` should have the following parameters: +The *tokenReadyCallback* function should have the following parameters: | Parameter | Type | Description | | --- | --- | --- | -| `token` | *string* | String representation of access token | -| `error` | *string* | String with error details, `null` in case of success | +| *token* | String | String representation of the access token | +| *error* | String | Error details, or `null` in the case of success | -and `notifyUserCallback` should have two parameters: +The *notifyUserCallback* function should have the following parameters: | Parameter | Type | Description | | --- | --- | --- | -| `uri` | *string* | The URI the user need to use for client authorization | -| `code` | *string* | The code for the authorization server | +| *url* | String | The URL the user needs to use for client authorization | +| *code* | String | The code for the authorization server | #### Example -Using `client` from previous [sample](#device-flow-client-creation-example) - ```squirrel client.acquireAccessToken( + // Token Ready Callback function(resp, err) { - server.log(resp); if (err) { server.error(err); + } else { + server.log(resp); } }, + // User notification callback function(url, code) { server.log("Authorization is pending. Please grant access."); server.log("URL: " + url); @@ -295,15 +275,13 @@ client.acquireAccessToken( ``` ### getValidAccessTokeOrNull() -Immediately returns either existing access token if it's valid, or null if it expired or -the client is not authorized yet. +This method immediately returns either an existing access token if it is valid, or `null` if the token has expired or the client is yet not authorized. #### Example -Using `client` from the first [sample](#device-flow-client-creation-example) - ```squirrel local token = client.getValidAccessTokeOrNull(); + if (token) { server.log("Token is valid: " + token); } else { @@ -313,75 +291,71 @@ if (token) { ### isTokenValid() -Checks if access token is valid. +This method checks if the current access token is valid. It returns `true` if this the case, or `false` if the token is no longer valid. #### Example -Using `client` from the first [sample](#device-flow-client-creation-example) - ```squirrel -server.log("Token is valid: " + client.isTokenValid()); +server.log("The access token is " + (client.isTokenValid() ? "valid" : "invalid")); ``` ### isAuthorized() -Checks if the client is authorized and able to refresh expired access token. +This method checks if the client is authorized and able to refresh an expired access token. -Using `client` from the first [sample](#device-flow-client-creation-example) +#### Example ```squirrel server.log("Client is authorized: " + client.isAuthorized()); +server.log("The client is " + (client.isAuthorized() ? "authorized" : "unauthorized")); ``` -### refreshAccessToken(tokenReadyCallback) +### refreshAccessToken(*tokenReadyCallback*) -Asynchronously refreshes access token and invokes `tokenReadyCallback` when done or an error occurs. - -Function `tokenReadyCallback` should have two parameters: +This method asynchronously refreshes the access token and invokes the function passed into the *tokenReadyCallback* parameter when this has been completed, or an error occurs. The *tokenReadyCallback* function has two parameters: | Parameter | Type | Description | | --- | --- | --- | -| token | String | String representation of access token | -| error | String | String with error details, `null` in case of success | +| *token* | String | The access token | +| *error* | String | Error details, or `null` in the case of success | #### Example -Using `client` from the first [sample](#device-flow-client-creation-example) - ```squirrel client.refreshAccessToken( function(resp, err) { - server.log(resp); if (err) { server.error(err); + } else { + server.log(resp); } } ); ``` -## Complete usage sample - -To connect all the parts together and show a sample of common case of library usage let's take a look a following sample +## Complete Example ```squirrel #require "OAuth2.agent.lib.nut:1.0.0 // Fill CLIENT_ID and CLIENT_SECRET with correct values local userConfig = { - "clientId" : "CLIENT_ID", - "clientSecret" : "CLIENT_SECRET", + "clientId" : "", + "clientSecret" : "", "scope" : "email profile", }; -// Initializing client with provided Google Firebase config +// Initialize client with provided Google Firebase config client <- OAuth2.DeviceFlow.Client(OAuth2.DeviceFlow.GOOGLE, userConfig); local token = client.getValidAccessTokeOrNull(); + if (token != null) { server.log("Valid access token is: " + token); } else { - // Starting procedure of access token acquisition + // Acquire a new access token local error = client.acquireAccessToken( + // Token received callback function function(resp, err) { if (err) { server.error("Token acquisition error: " + err); @@ -389,6 +363,7 @@ if (token != null) { server.log("Received token: " + resp); } }, + // User notification callback function function(url, code) { server.log("Authorization is pending. Please grant access."); server.log("URL: " + url); @@ -396,14 +371,12 @@ if (token != null) { } ); - if (null != error) server.error("Failed to obtain token: " + error); + if (error != null) server.error("Failed to obtain token: " + error); } ``` -**NOTE:** The DeviceFlow Client was verified and tested on the Google [Firebase](https://firebase.google.com) - authorization flow. - +**Note** The DeviceFlow Client was verified and tested using the Google [Firebase](https://firebase.google.com) authorization flow. # License -The OAuth library is licensed under the [MIT License](LICENSE). \ No newline at end of file +The OAuth library is licensed under the [MIT License](LICENSE). From 8c1a9efd4f458bcdb5179018783158cd7a3ca75e Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Tue, 20 Jun 2017 11:24:31 +0100 Subject: [PATCH 02/11] Further edits --- README.md | 58 ++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index f2470a8..56163db 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,25 @@ # OAuth 2.0 -OAuth 2.0 authentication and authorization flows implementation. The library supports -the following flows: -- [OAuth2.JWTProfile.Client](#oauth2jwtprofileclient) — OAuth 2.0 with JSON Web Token (JWT) Profile for Client Authentication and Authorization Grants - defined in the [IETF RFC 7523](https://tools.ietf.org/html/rfc7523). -- [OAuth2.DeviceFlow.Client](#oauth2deviceflowclient) — Device Flow for browserless and input constrained devices. The implementation conforms -to the [draft specification](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05). +This library provides OAuth 2.0 authentication and authorization flows. It supports the following flows: -The library exposes access token for applications and hides provider specific -operations including refresh token management and expired access token renewal. +- [OAuth2.JWTProfile.Client](#oauth2jwtprofileclient) — OAuth 2.0 with the JSON Web Token (JWT) Profile for Client Authentication and Authorization Grants as defined in [IETF RFC 7523](https://tools.ietf.org/html/rfc7523). +- [OAuth2.DeviceFlow.Client](#oauth2deviceflowclient) — OAuth 2.0 Device Flow for browserless and input-constrained devices. The implementation conforms to the [IETF draft device flow specification](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05). + +The library exposes retrieved access tokens for applications and hides provider-specific operations, including the renewal of expired tokens. **To add this library to your project, add** `#require "OAuth2.agent.lib.nut:1.0.0"` **to the top of your agent code.** ## OAuth2.JWTProfile.Client -The class implements OAuth 2.0 flow using JSON Web Token (JWT) Bearer Token as a means for requesting an access token and for client authentication. +This class implements an OAuth 2.0 client flow using a JSON Web Token (JWT) as the means for requesting access tokens and for client authentication. -**Note** The flow requires RSA-SHA256 signature, which is not currently supported by the Electric Imp [imp API](https://electricimp.com/docs/api/). As a temporary solution we suggest that you use an [AWS Lambda](https://aws.amazon.com/lambda) function that will do [RSA-SHA256 signatures](examples#amazon-lambda-for-rsa-sha256-signatures) for an agent. AWS Lambda is subject to a service charge so please refer to the Amazon pricing -[page](https://aws.amazon.com/lambda/pricing/) for more information. +**Note** The flow requires an RSA-SHA256 signature which is not currently supported by the Electric Imp [imp API](https://electricimp.com/docs/api/). As a temporary solution we suggest that you use an [AWS Lambda](https://aws.amazon.com/lambda) function that will perform [RSA-SHA256 signatures](examples#amazon-lambda-for-rsa-sha256-signatures) for an agent. However, please note that AWS Lambda is subject to a service charge so you should refer to the Amazon pricing [page](https://aws.amazon.com/lambda/pricing/) for more information before proceeding. ## OAuth2.JWTProfile.Client Usage ### constructor(*providerSettings, userSettings*) -The constructor creates an instance of an *OAuth2.JWTProfile.Client* object. The first parameter, *providerSettings*, is a map that contains provider-specific settings: +The constructor creates an instance of the *OAuth2.JWTProfile.Client* class. The first parameter, *providerSettings*, is a map that contains provider-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | @@ -33,8 +29,8 @@ The second parameter, *userSettings*, defines a map with user- and application-s | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| *iss* | String | Required | The JSON Web Token issuer | -| *scope* | String | Required | Scopes enable your application to request access only to the resources that it needs while also enabling users to control the amount of access that they grant to your application | +| *iss* | String | Required | The JWT issuer | +| *scope* | String | Required | A scope. Scopes enable your application to request access only to the resources that it needs while also enabling users to control the amount of access that they grant to your application | | *jwtSignKey* | String | Required | A JWT sign secret key | | *rs256signer* | *[AWSLambda](https://github.com/electricimp/awslambda)* | Required | Instance of [AWSLambda](https://github.com/electricimp/awslambda) for RSA-SHA256 encryption. You can use [this example code](examples#jwt-profile-for-oauth-20) to create the AWS Lambda function | | *sub* | String | Optional. *Default:* the value of `iss` | The *subject* of the JWT. Google seems to ignor this field. | @@ -74,32 +70,31 @@ local userSettings = { local client = OAuth2.JWTProfile.Client(providerSettings, userSettings); ``` + **Important** The name of the AWS Lambda function **must** be `RSALambda`. ## OAuth2.JWTProfile.Client Methods ### acquireAccessToken(*tokenReadyCallback*) -This method begins the access-token acquisition procedure. It invokes the provided callback function immediately if the access token is available and valid. +This method begins the access-token acquisition procedure. It invokes the provided callback function immediately if the access token is already available and valid. The function passed into *tokenReadyCallback* should have two parameters if its own: | Parameter | Type | Description | | --- | --- | --- | -| *token* | String | String representation of the access token | -| *error* | String | String with error details, otherwise `null` in the case of success | +| *token* | String | The access token | +| *error* | String | Error details, or `null` in the case of success | #### Example -Using *client* from the [construction example](#jwt-profile-client-creation-example): - ```squirrel client.acquireAccessToken( - function(resp, err) { - if (err) { - server.error(err); + function(token, error) { + if (error) { + server.error(error); } else { - server.log("Access Token: " + resp); + server.log("The access token has the value: " + token); } } ); @@ -107,7 +102,7 @@ client.acquireAccessToken( ### getValidAccessTokeOrNull() -This method returns an access token string in a non-blocking way. It returns the access token as a string if the token is valid, or `null` if the client is not authorized or the token has expired. +This method returns an access token string in a non-blocking way. It returns `null` if the client is not authorized or the token has expired. #### Example @@ -115,9 +110,9 @@ This method returns an access token string in a non-blocking way. It returns the local token = client.getValidAccessTokeOrNull(); if (token) { - server.log("token is valid and has value: " + token); + server.log("The access token is valid and has the value: " + token); } else { - server.log("token is either expired or client is not authorized!"); + server.log("The access token has either expired or the client is not authorized"); } ``` @@ -140,8 +135,8 @@ server.log("The access token is " + (client.isTokenValid() ? "valid" : "invalid" // Substitute with real values const LAMBDA_REGION = "us-west-1"; -const LAMBDA_ACCESS_KEY_ID = ""; -const LAMBDA_ACCESS_KEY = ""; +const LAMBDA_ACCESS_KEY_ID = ""; +const LAMBDA_ACCESS_KEY = ""; const GOOGLE_ISS = "rsalambda@quick-cacao-168121.iam.gserviceaccount.com"; const GOOGLE_SECRET_KEY = "-----BEGIN PRIVATE KEY-----\nprivate key goes here\n-----END PRIVATE KEY-----\n"; @@ -162,15 +157,16 @@ local client = OAuth2.JWTProfile.Client(providerSettings, userSettings); local token = client.getValidAccessTokeOrNull(); if (token != null) { + // We have a valid token already server.log("Valid access token is: " + token); } else { - // Starting procedure of access token acquisition + // Acquire a new access token local error = client.acquireAccessToken( - function(resp, err) { + function(newToken, err) { if (err) { server.error("Token acquisition error: " + err); } else { - server.log("Received token: " + resp); + server.log("Received a new token: " + newToken); } } ); From 92c1609c50af874842cfe2c2df089511956873b9 Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Tue, 20 Jun 2017 11:31:56 +0100 Subject: [PATCH 03/11] Further edits #2 --- README.md | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 56163db..f89e6d8 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,13 @@ This class implements an OAuth 2.0 client flow using a JSON Web Token (JWT) as t ### constructor(*providerSettings, userSettings*) -The constructor creates an instance of the *OAuth2.JWTProfile.Client* class. The first parameter, *providerSettings*, is a map that contains provider-specific settings: +The constructor creates an instance of the *OAuth2.JWTProfile.Client* class. The first parameter, *providerSettings*, is a table that contains provider-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | | *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | -The second parameter, *userSettings*, defines a map with user- and application-specific settings: +The second parameter, *userSettings*, defines a table with user- and application-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | @@ -161,7 +161,7 @@ if (token != null) { server.log("Valid access token is: " + token); } else { // Acquire a new access token - local error = client.acquireAccessToken( + client.acquireAccessToken( function(newToken, err) { if (err) { server.error("Token acquisition error: " + err); @@ -170,8 +170,6 @@ if (token != null) { } } ); - - if (error != null) server.error("Failed to obtain token: " + error); } ``` @@ -179,13 +177,13 @@ if (token != null) { ## OAuth2.DeviceFlow.Client -This class implements an OAuth 2.0 authorization flow for browserless and/or input-constrained devices. Often referred to as the [device flow](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05), this flow enables OAuth clients to request user authorization from devices that have an Internet connection, but lack a suitable input method or web browser for a more traditional OAuth flow. This authorization flow therefore instructs the user to perform the authorization request on a secondary device, such as a smartphone. +This class implements an OAuth 2.0 authorization flow for browserless and/or input-constrained devices. Often referred to as the [device flow](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-05), this flow enables OAuth clients to request user authorization from devices that have an Internet connection but lack a suitable input method or web browser required for a more traditional OAuth flow. This authorization flow therefore instructs the user to perform the authorization request on a secondary device, such as a smartphone. ## OAuth2.DeviceFlow.Client Usage ### constructor(*providerSettings, userSettings*) -This constructor creates an instance of the *OAuth2.DeviceFlow.Client* class. The first parameter, *providerSettings*, is a map that contains provider-specific settings: +This constructor creates an instance of the *OAuth2.DeviceFlow.Client* class. The first parameter, *providerSettings*, is a table that contains provider-specific settings: | Parameter | Type | Use | Description | | --- | --- | --- | --- | @@ -193,7 +191,7 @@ This constructor creates an instance of the *OAuth2.DeviceFlow.Client* class. Th | *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | | *GRANT_TYPE* | String | Optional. Default: `"urn:ietf:params:oauth:grant-type:device_code"` | The grant type identifier supported by the provider | -The second parameter, *userSettings*, defines a map with user- and application-specific settings: +The second parameter, *userSettings*, takes a table containing user- and application-specific settings: | Parameter | Type | Use |Description | | --- | --- | --- | --- | @@ -225,7 +223,7 @@ client <- OAuth2.DeviceFlow.Client(providerSettings, userSettings); ### acquireAccessToken(*tokenReadyCallback, notifyUserCallback, force*) -This methiod begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message otherwise. The access token is delivered through the function passed into the *tokenReadyCallback* function. +This method begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message otherwise. The access token is delivered through the function passed into the *tokenReadyCallback* function. Parameter details: @@ -302,13 +300,12 @@ This method checks if the client is authorized and able to refresh an expired ac #### Example ```squirrel -server.log("Client is authorized: " + client.isAuthorized()); server.log("The client is " + (client.isAuthorized() ? "authorized" : "unauthorized")); ``` ### refreshAccessToken(*tokenReadyCallback*) -This method asynchronously refreshes the access token and invokes the function passed into the *tokenReadyCallback* parameter when this has been completed, or an error occurs. The *tokenReadyCallback* function has two parameters: +This method asynchronously refreshes the access token and invokes the function passed into the *tokenReadyCallback* parameter when this has been completed or an error occurs. The *tokenReadyCallback* function has two parameters: | Parameter | Type | Description | | --- | --- | --- | @@ -319,11 +316,11 @@ This method asynchronously refreshes the access token and invokes the function p ```squirrel client.refreshAccessToken( - function(resp, err) { + function(token, err) { if (err) { - server.error(err); + server.error("Token refresh error: " + err); } else { - server.log(resp); + server.log("The access token is refreshed. It has the value: " + token); } } ); @@ -350,7 +347,7 @@ if (token != null) { server.log("Valid access token is: " + token); } else { // Acquire a new access token - local error = client.acquireAccessToken( + client.acquireAccessToken( // Token received callback function function(resp, err) { if (err) { @@ -366,8 +363,6 @@ if (token != null) { server.log("CODE: " + code); } ); - - if (error != null) server.error("Failed to obtain token: " + error); } ``` From eb46a20c105d3bd7b147b9d56eed24005c98cf7c Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Tue, 20 Jun 2017 11:37:49 +0100 Subject: [PATCH 04/11] Small edits --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f89e6d8..9002a58 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ client <- OAuth2.DeviceFlow.Client(providerSettings, userSettings); ### acquireAccessToken(*tokenReadyCallback, notifyUserCallback, force*) -This method begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message otherwise. The access token is delivered through the function passed into the *tokenReadyCallback* function. +This method begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message if the client is already performing a request and the *force* directive is set. The access token is delivered through the function passed into the *tokenReadyCallback* function. Parameter details: @@ -347,7 +347,7 @@ if (token != null) { server.log("Valid access token is: " + token); } else { // Acquire a new access token - client.acquireAccessToken( + local error = client.acquireAccessToken( // Token received callback function function(resp, err) { if (err) { @@ -363,6 +363,8 @@ if (token != null) { server.log("CODE: " + code); } ); + + if (error != null) server.error("Client is already performing request (" + error + ")"); } ``` From 8c37de8ab0fc9e4aa58b8693018e40781509788e Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Tue, 20 Jun 2017 11:45:57 +0100 Subject: [PATCH 05/11] Spell check --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9002a58..cd11fb8 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The second parameter, *userSettings*, defines a table with user- and application | *scope* | String | Required | A scope. Scopes enable your application to request access only to the resources that it needs while also enabling users to control the amount of access that they grant to your application | | *jwtSignKey* | String | Required | A JWT sign secret key | | *rs256signer* | *[AWSLambda](https://github.com/electricimp/awslambda)* | Required | Instance of [AWSLambda](https://github.com/electricimp/awslambda) for RSA-SHA256 encryption. You can use [this example code](examples#jwt-profile-for-oauth-20) to create the AWS Lambda function | -| *sub* | String | Optional. *Default:* the value of `iss` | The *subject* of the JWT. Google seems to ignor this field. | +| *sub* | String | Optional. *Default:* the value of *iss* | The subject of the JWT. **Note** Google seems to ignore this field | **Note** When omitted, the optional *sub* property is substituted by the mandatory *iss* property. @@ -223,7 +223,7 @@ client <- OAuth2.DeviceFlow.Client(providerSettings, userSettings); ### acquireAccessToken(*tokenReadyCallback, notifyUserCallback, force*) -This method begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been aquired. It returns `null` in the case of success, or an error message if the client is already performing a request and the *force* directive is set. The access token is delivered through the function passed into the *tokenReadyCallback* function. +This method begins the access-token acquisition procedure. Depending on the client state, it may start a full client authorization procedure or just refresh a token that has already been acquired. It returns `null` in the case of success, or an error message if the client is already performing a request and the *force* directive is set. The access token is delivered through the function passed into the *tokenReadyCallback* function. Parameter details: @@ -252,11 +252,11 @@ The *notifyUserCallback* function should have the following parameters: ```squirrel client.acquireAccessToken( // Token Ready Callback - function(resp, err) { + function(token, err) { if (err) { - server.error(err); + server.error("Token retrieval error: " + err); } else { - server.log(resp); + server.log("The access token: " + token); } }, // User notification callback @@ -267,6 +267,7 @@ client.acquireAccessToken( } ); ``` + ### getValidAccessTokeOrNull() This method immediately returns either an existing access token if it is valid, or `null` if the token has expired or the client is yet not authorized. From f9b41eb661dd0e0b39034c2bc6c28f6b32131d12 Mon Sep 17 00:00:00 2001 From: Tony Smith Date: Thu, 22 Jun 2017 11:35:25 +0100 Subject: [PATCH 06/11] Fix small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd11fb8..5c9008a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ local client = OAuth2.JWTProfile.Client(providerSettings, userSettings); This method begins the access-token acquisition procedure. It invokes the provided callback function immediately if the access token is already available and valid. -The function passed into *tokenReadyCallback* should have two parameters if its own: +The function passed into *tokenReadyCallback* should have two parameters of its own: | Parameter | Type | Description | | --- | --- | --- | From 2f31f4afd3c2a505d77e1bbb1e5b9b3741ef556e Mon Sep 17 00:00:00 2001 From: Pavel Petroshenko Date: Thu, 22 Jun 2017 12:46:12 -0700 Subject: [PATCH 07/11] Review comments addressed: fixed a typo in the functions name + use locaCamelCase for parameter names. --- OAuth2.agent.lib.nut | 39 +++++++++++++++++++++------------------ README.md | 20 ++++++++++---------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/OAuth2.agent.lib.nut b/OAuth2.agent.lib.nut index 2dcd6f9..d5a57ab 100644 --- a/OAuth2.agent.lib.nut +++ b/OAuth2.agent.lib.nut @@ -79,7 +79,7 @@ class OAuth2.JWTProfile { // Parameters: // provider OAuth2 provider configuration // Must be a table with following set of strings: - // TOKEN_HOST - provider's token endpoint URI + // tokenHost - provider's token endpoint URI // params Client specific parameters // Must be a table with following set of strings: // iss - JWT issuer @@ -89,10 +89,10 @@ class OAuth2.JWTProfile { // https://github.com/electricimp/AWSLambda/blob/master/examples/RSACrypto#setting-up-the-aim-user // sub - [optional] the subject of the JWT constructor(provider, user) { - if (!("TOKEN_HOST" in provider) ) { + if (!("tokenHost" in provider) ) { throw "Invalid Provider"; } - _tokenHost = provider.TOKEN_HOST; + _tokenHost = provider.tokenHost; if (!("iss" in user) || !("scope" in user) || @@ -104,8 +104,11 @@ class OAuth2.JWTProfile { _iss = user.iss; // mandatory field but GOOGLE skips it - if ("sub" in user) _sub = user.sub; - else _sub = _iss; + if ("sub" in user) { + _sub = user.sub; + } else { + _sub = _iss; + } _scope = user.scope; _jwtSignKey = user.jwtSignKey; @@ -116,7 +119,7 @@ class OAuth2.JWTProfile { // Returns: // Access token as string object // Null if the client is not authorized or token is expired - function getValidAccessTokeOrNull() { + function getValidAccessTokenOrNull() { if (isTokenValid()) { return _accessToken; } else { @@ -296,9 +299,9 @@ class OAuth2.DeviceFlow { // Predefined configuration for Google Authorization service GOOGLE = { - "LOGIN_HOST" : "https://accounts.google.com/o/oauth2/device/code", - "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token", - "GRANT_TYPE" : "http://oauth.net/grant_type/device/1.0", + "loginHost" : "https://accounts.google.com/o/oauth2/device/code", + "tokenHost" : "https://www.googleapis.com/oauth2/v4/token", + "grantType" : "http://oauth.net/grantType/device/1.0", }; // The class that represents OAuth2 Client role. @@ -349,23 +352,23 @@ class OAuth2.DeviceFlow { // Parameters: // provider OAuth2 provider configuration // Must be a table with following set of strings: - // LOGIN_HOST - provider's device authorization endpoint URI - // TOKEN_HOST - provider's token endpoint URI - // GRANT_TYPE - [optional] grant type + // loginHost - provider's device authorization endpoint URI + // tokenHost - provider's token endpoint URI + // grantType - [optional] grant type // params Client specific parameters // Must be a table with following set of strings: // clientId - client identifier // scope - authorization scope // clientSecret- [optional] client secret (password) constructor(provider, params) { - if ( !("LOGIN_HOST" in provider) || - !("TOKEN_HOST" in provider) ) { + if ( !("loginHost" in provider) || + !("tokenHost" in provider) ) { throw "Invalid Provider"; } - _loginHost = provider.LOGIN_HOST; - _tokenHost = provider.TOKEN_HOST; + _loginHost = provider.loginHost; + _tokenHost = provider.tokenHost; - if ("GRANT_TYPE" in provider) _grantType = provider.GRANT_TYPE; + if ("grantType" in provider) _grantType = provider.grantType; if (!("clientId" in params) || !("scope" in params)) throw "Invalid Config"; @@ -380,7 +383,7 @@ class OAuth2.DeviceFlow { // Returns: // Access token as string object // Null if the client is not authorized or token is expired - function getValidAccessTokeOrNull() { + function getValidAccessTokenOrNull() { if (isAuthorized() && isTokenValid()) { return _accessToken; } else { diff --git a/README.md b/README.md index cd11fb8..eedcd8e 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The constructor creates an instance of the *OAuth2.JWTProfile.Client* class. The | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | +| *tokenHost* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | The second parameter, *userSettings*, defines a table with user- and application-specific settings: @@ -58,7 +58,7 @@ const GOOGLE_SECRET_KEY = "-----BEGIN PRIVATE KEY-----\nprivate key goes here local signer = AWSLambda(LAMBDA_REGION, LAMBDA_ACCESS_KEY_ID, LAMBDA_ACCESS_KEY); local providerSettings = { - "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token" + "tokenHost" : "https://www.googleapis.com/oauth2/v4/token" }; local userSettings = { @@ -143,7 +143,7 @@ const GOOGLE_SECRET_KEY = "-----BEGIN PRIVATE KEY-----\nprivate key goes here local signer = AWSLambda(LAMBDA_REGION, LAMBDA_ACCESS_KEY_ID, LAMBDA_ACCESS_KEY); local providerSettings = { - "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token" + "tokenHost" : "https://www.googleapis.com/oauth2/v4/token" }; local userSettings = { @@ -187,9 +187,9 @@ This constructor creates an instance of the *OAuth2.DeviceFlow.Client* class. Th | Parameter | Type | Use | Description | | --- | --- | --- | --- | -| *LOGIN_HOST* | String | Required | The authorization endpoint. This is used by the client to obtain authorization from the resource owner via user-agent redirection | -| *TOKEN_HOST* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | -| *GRANT_TYPE* | String | Optional. Default: `"urn:ietf:params:oauth:grant-type:device_code"` | The grant type identifier supported by the provider | +| *loginHost* | String | Required | The authorization endpoint. This is used by the client to obtain authorization from the resource owner via user-agent redirection | +| *tokenHost* | String | Required | The token endpoint. This is used by the client to exchange an authorization grant for an access token, typically with client authentication | +| *grantType* | String | Optional. Default: `"urn:ietf:params:oauth:grant-type:device_code"` | The grant type identifier supported by the provider | The second parameter, *userSettings*, takes a table containing user- and application-specific settings: @@ -199,15 +199,15 @@ The second parameter, *userSettings*, takes a table containing user- and applica | *clientSecret* | String | Required | The project's client secret | | *scope* | String | Required | A scope. Scopes enable your application to only request access to the resources that it needs while also enabling users to control the amount of access that they grant to your application | -The library provides predefined configuration settings for the Google Device Auth flow. These settings are defined in the provider-specific settings map: *OAuth2.DeviceFlow.GOOGLE*. This table provides pre-populated *LOGIN_HOST, TOKEN_HOST* and *GRANT_TYPE* values. +The library provides predefined configuration settings for the Google Device Auth flow. These settings are defined in the provider-specific settings map: *OAuth2.DeviceFlow.GOOGLE*. This table provides pre-populated *loginHost, tokenHost* and *grantType* values. #### Device Flow Client Creation Example ```squirrel local providerSettings = { - "LOGIN_HOST" : "https://accounts.google.com/o/oauth2/device/code", - "TOKEN_HOST" : "https://www.googleapis.com/oauth2/v4/token", - "GRANT_TYPE" : "http://oauth.net/grant_type/device/1.0", + "loginHost" : "https://accounts.google.com/o/oauth2/device/code", + "tokenHost" : "https://www.googleapis.com/oauth2/v4/token", + "grantType" : "http://oauth.net/grantType/device/1.0", }; local userSettings = { From acab2b535effc24f53df8d5646a9f5d06513c0dc Mon Sep 17 00:00:00 2001 From: Pavel Petroshenko Date: Thu, 22 Jun 2017 15:01:22 -0700 Subject: [PATCH 08/11] getValidAccessTokeOrNull->getValidAccessTokenOrNull --- README.md | 12 ++++++------ examples/DeviceFlowGoogle.agent.nut | 2 +- examples/JWTGooglePubSub.agent.nut | 2 +- tests/DeviceFlowGoogleTestCase.agent.test.nut | 2 +- tests/GooglePubSubJWTAuth.agent.test.nut | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a722b86..53d6efb 100644 --- a/README.md +++ b/README.md @@ -100,14 +100,14 @@ client.acquireAccessToken( ); ``` -### getValidAccessTokeOrNull() +### getValidAccessTokenOrNull() This method returns an access token string in a non-blocking way. It returns `null` if the client is not authorized or the token has expired. #### Example ```squirrel -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token) { server.log("The access token is valid and has the value: " + token); @@ -155,7 +155,7 @@ local userSettings = { local client = OAuth2.JWTProfile.Client(providerSettings, userSettings); -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token != null) { // We have a valid token already server.log("Valid access token is: " + token); @@ -268,14 +268,14 @@ client.acquireAccessToken( ); ``` -### getValidAccessTokeOrNull() +### getValidAccessTokenOrNull() This method immediately returns either an existing access token if it is valid, or `null` if the token has expired or the client is yet not authorized. #### Example ```squirrel -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token) { server.log("Token is valid: " + token); @@ -342,7 +342,7 @@ local userConfig = { // Initialize client with provided Google Firebase config client <- OAuth2.DeviceFlow.Client(OAuth2.DeviceFlow.GOOGLE, userConfig); -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token != null) { server.log("Valid access token is: " + token); diff --git a/examples/DeviceFlowGoogle.agent.nut b/examples/DeviceFlowGoogle.agent.nut index b51eb9e..8fe8ac8 100644 --- a/examples/DeviceFlowGoogle.agent.nut +++ b/examples/DeviceFlowGoogle.agent.nut @@ -37,7 +37,7 @@ local userConfig = { // Initializing client with provided Google Firebase config client <- OAuth2.DeviceFlow.Client(OAuth2.DeviceFlow.GOOGLE, userConfig); -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token != null) { server.log("Valid access token is: " + token); } else { diff --git a/examples/JWTGooglePubSub.agent.nut b/examples/JWTGooglePubSub.agent.nut index 5f89adf..086ac47 100644 --- a/examples/JWTGooglePubSub.agent.nut +++ b/examples/JWTGooglePubSub.agent.nut @@ -44,7 +44,7 @@ local config = { // Initializing client with provided Google Firebase config client <- OAuth2.JWTProfile.Client(OAuth2.DeviceFlow.GOOGLE, config); -local token = client.getValidAccessTokeOrNull(); +local token = client.getValidAccessTokenOrNull(); if (token != null) { server.log("Valid access token is: " + token); } else { diff --git a/tests/DeviceFlowGoogleTestCase.agent.test.nut b/tests/DeviceFlowGoogleTestCase.agent.test.nut index b684185..838227b 100644 --- a/tests/DeviceFlowGoogleTestCase.agent.test.nut +++ b/tests/DeviceFlowGoogleTestCase.agent.test.nut @@ -94,7 +94,7 @@ class DeviceFlowGoogleTestCase extends ImpTestCase { function testRunCommandAsynchronously() { return Promise(function (success, failure) { - local token = auth.getValidAccessTokeOrNull(); + local token = auth.getValidAccessTokenOrNull(); if (null != token) { server.log("VerifyTokenTest: it was not null!. something went wrong!"); checkToken(token, success, failure); diff --git a/tests/GooglePubSubJWTAuth.agent.test.nut b/tests/GooglePubSubJWTAuth.agent.test.nut index 5897783..40fa798 100644 --- a/tests/GooglePubSubJWTAuth.agent.test.nut +++ b/tests/GooglePubSubJWTAuth.agent.test.nut @@ -83,7 +83,7 @@ class GooglePubSubJWTAuth extends ImpTestCase { function testAcquireAndVerifyToken() { return Promise(function (success, failure) { - local token = auth.getValidAccessTokeOrNull(); + local token = auth.getValidAccessTokenOrNull(); if (null != token) { server.log("VerifyTokenTest: it was not null!. something went wrong!"); failure("Initial token is not null"); From 651f6dcec2605ac7874ce86fc11e483da35e713a Mon Sep 17 00:00:00 2001 From: Pavel Petroshenko Date: Thu, 22 Jun 2017 15:10:54 -0700 Subject: [PATCH 09/11] Fixed grant_type epic bug. --- OAuth2.agent.lib.nut | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OAuth2.agent.lib.nut b/OAuth2.agent.lib.nut index d5a57ab..6373e92 100644 --- a/OAuth2.agent.lib.nut +++ b/OAuth2.agent.lib.nut @@ -301,7 +301,7 @@ class OAuth2.DeviceFlow { GOOGLE = { "loginHost" : "https://accounts.google.com/o/oauth2/device/code", "tokenHost" : "https://www.googleapis.com/oauth2/v4/token", - "grantType" : "http://oauth.net/grantType/device/1.0", + "grantType" : "http://oauth.net/grant_type/device/1.0", }; // The class that represents OAuth2 Client role. diff --git a/README.md b/README.md index 53d6efb..5b65d0a 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ The library provides predefined configuration settings for the Google Device Aut local providerSettings = { "loginHost" : "https://accounts.google.com/o/oauth2/device/code", "tokenHost" : "https://www.googleapis.com/oauth2/v4/token", - "grantType" : "http://oauth.net/grantType/device/1.0", + "grantType" : "http://oauth.net/grant_type/device/1.0", }; local userSettings = { From 9d085f0d4bfc693d20f9b2fb2927c18e60409033 Mon Sep 17 00:00:00 2001 From: Pavel Petroshenko Date: Thu, 22 Jun 2017 15:18:32 -0700 Subject: [PATCH 10/11] Cleanup logging. --- OAuth2.agent.lib.nut | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OAuth2.agent.lib.nut b/OAuth2.agent.lib.nut index 6373e92..8f31c78 100644 --- a/OAuth2.agent.lib.nut +++ b/OAuth2.agent.lib.nut @@ -173,7 +173,7 @@ class OAuth2.JWTProfile { "message" : header + "." + body }; - _log("Calling lambda:" + signrequest); + _log("Calling lambda..."); _signer.invoke({ "payload" : signrequest, "functionName" : "RSALambda" @@ -280,13 +280,13 @@ class OAuth2.JWTProfile { // Records non-error event function _log(message) { if (_debug) { - server.log("[OAuth2JWTProfile]" + message); + server.log("[OAuth2JWTProfile] " + message); } } // Records error event function _error(message) { - server.error("[OAuth2JWTProfile]" + message); + server.error("[OAuth2JWTProfile] " + message); } } @@ -811,12 +811,14 @@ class OAuth2.DeviceFlow { // Records error event function _error(txt) { - server.error(txt); + server.error("[OAuth2DeviceFlow] " + txt); } // Records non-error event function _log(txt) { - if (_debug) server.log(txt); + if (_debug) { + server.log("[OAuth2DeviceFlow] " + txt); + } } } // end of Client } \ No newline at end of file From f982aa777151fe383f851cf64912bbbba43a87d8 Mon Sep 17 00:00:00 2001 From: Pavel Petroshenko Date: Thu, 22 Jun 2017 15:20:31 -0700 Subject: [PATCH 11/11] Version udpated, some cleanup. --- OAuth2.agent.lib.nut | 2 +- README.md | 8 ++++---- examples/DeviceFlowGoogle.agent.nut | 2 +- examples/JWTGooglePubSub.agent.nut | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/OAuth2.agent.lib.nut b/OAuth2.agent.lib.nut index 8f31c78..75f66b9 100644 --- a/OAuth2.agent.lib.nut +++ b/OAuth2.agent.lib.nut @@ -40,7 +40,7 @@ enum Oauth2DeviceFlowState { // The class that introduces OAuth2 namespace class OAuth2 { - static VERSION = "1.0.0"; + static VERSION = "2.0.0"; } // The class that represents OAuth 2.0 authorization flow diff --git a/README.md b/README.md index 5b65d0a..8f236e4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This library provides OAuth 2.0 authentication and authorization flows. It suppo The library exposes retrieved access tokens for applications and hides provider-specific operations, including the renewal of expired tokens. -**To add this library to your project, add** `#require "OAuth2.agent.lib.nut:1.0.0"` **to the top of your agent code.** +**To add this library to your project, add** `#require "OAuth2.agent.lib.nut:2.0.0"` **to the top of your agent code.** ## OAuth2.JWTProfile.Client @@ -45,7 +45,7 @@ The second parameter, *userSettings*, defines a table with user- and application #require "AWSLambda.agent.lib.nut:1.0.0" // OAuth 2.0 library -#require "OAuth2.agent.lib.nut:1.0.0" +#require "OAuth2.agent.lib.nut:2.0.0" // Substitute with real values const LAMBDA_REGION = "us-west-1"; @@ -131,7 +131,7 @@ server.log("The access token is " + (client.isTokenValid() ? "valid" : "invalid" ```squirrel #require "AWSRequestV4.class.nut:1.0.2" #require "AWSLambda.agent.lib.nut:1.0.0" -#require "OAuth2.agent.lib.nut:1.0.0 +#require "OAuth2.agent.lib.nut:2.0.0 // Substitute with real values const LAMBDA_REGION = "us-west-1"; @@ -330,7 +330,7 @@ client.refreshAccessToken( ## Complete Example ```squirrel -#require "OAuth2.agent.lib.nut:1.0.0 +#require "OAuth2.agent.lib.nut:2.0.0 // Fill CLIENT_ID and CLIENT_SECRET with correct values local userConfig = { diff --git a/examples/DeviceFlowGoogle.agent.nut b/examples/DeviceFlowGoogle.agent.nut index 8fe8ac8..23685e3 100644 --- a/examples/DeviceFlowGoogle.agent.nut +++ b/examples/DeviceFlowGoogle.agent.nut @@ -22,7 +22,7 @@ // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. -#require "OAuth2.agent.lib.nut:1.0.0" +#require "OAuth2.agent.lib.nut:2.0.0" const CLIENT_ID = ""; const CLIENT_SECRET = ""; diff --git a/examples/JWTGooglePubSub.agent.nut b/examples/JWTGooglePubSub.agent.nut index 086ac47..4d440bb 100644 --- a/examples/JWTGooglePubSub.agent.nut +++ b/examples/JWTGooglePubSub.agent.nut @@ -25,7 +25,7 @@ #require "AWSRequestV4.class.nut:1.0.2" #require "AWSLambda.agent.lib.nut:1.0.0" //@include "../OAuth2.agent.lib.nut" -#require "OAuth2.agent.lib.nut:1.0.0" +#require "OAuth2.agent.lib.nut:2.0.0" const GOOGLE_ISS = ""; const GOOGLE_SECRET_KEY = "";