Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Algo tushar Added Google Authentication #302

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Contributors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Contributors

A list of contributors who have contributed to this project:

- [Abubakar Wazih Tushar](https://github.com/algo-tushar) - Added Google authentication feature using access_token or id_token.
- [Enrique Chavez](https://github.com/Tmeister) - Original project owner.
65 changes: 64 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ When the plugin is activated, a new namespace is added.
```


Also, two new endpoints are added to this namespace.
Also, three new endpoints are added to this namespace.


| Endpoint | HTTP Verb |
| ------------------------------------- | --------- |
| */wp-json/jwt-auth/v1/token* | POST |
| */wp-json/jwt-auth/v1/google_auth* | POST |
| */wp-json/jwt-auth/v1/token/validate* | POST |

## Usage
Expand Down Expand Up @@ -150,6 +151,68 @@ Error response from the server:
}
```



### /wp-json/jwt-auth/v1/google_auth

This is the entry point for the JWT Authentication using **Google Access** Token or **Id Token**.

Receive a Google token as `token` and `type`, where `type` is either `id_token` or `access_token`. Validate the Google token and return a JWT for future API requests if authentication is successful, or an error if authentication fails.

#### Sample request using AngularJS

```javascript

( function() {
var app = angular.module( 'jwtAuth', [] );

app.controller( 'MainController', function( $scope, $http ) {

var apiHost = 'http://yourdomain.com/wp-json';

$http.post( apiHost + '/jwt-auth/v1/google_auth', {
type: 'id_token', // access_token or id_token
token: 'token' // your token response from google oauth2
} )

.then( function( response ) {
console.log( response.data )
} )

.catch( function( error ) {
console.error( 'Error', error.data[0] );
} );

} );

} )();


```

Success response from the server:

```json
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0L3dwMSIsImlhdCI6MTcxNjU4ODQ5NywibmJmIjoxNzE2NTg4NDk3LCJleHAiOjE3MTcxOTMyOTcsImRhdGEiOnsidXNlciI6eyJpZCI6Mn19fQ.-S9btuiTT1VKJUMIPYw_TJDM6_ExhSCsWnV7H1LEw6g",
"user_display_name": "someuser",
"user_email": "[email protected]",
"user_nicename": "someuser"
}
```

Error response from the server:

```json
{
"code": "jwt_google_auth_error",
"data": {
"status": 403
},
"message": "Failed to authenticate. Check the `token` and `type`"
}
```

Once you get the token, you must store it somewhere in your application, e.g. in a **cookie** or using **localstorage**.

From this point, you should pass this token to every API call.
Expand Down
182 changes: 178 additions & 4 deletions public/class-jwt-auth-public.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ public function add_api_routes() {
'permission_callback' => '__return_true',
] );

// Register new route for authenticate google oauth2 response
register_rest_route( $this->namespace, 'google_auth', [
'methods' => 'POST',
'callback' => [ $this, 'google_authenticate' ],
'permission_callback' => '__return_true',
] );

register_rest_route( $this->namespace, 'token/validate', [
'methods' => 'POST',
'callback' => [ $this, 'validate_token' ],
Expand Down Expand Up @@ -163,7 +170,7 @@ public function generate_token( WP_REST_Request $request ) {
'exp' => $expire,
'data' => [
'user' => [
'id' => $user->data->ID,
'id' => $user->ID,
],
],
];
Expand Down Expand Up @@ -191,9 +198,176 @@ public function generate_token( WP_REST_Request $request ) {
/** The token is signed, now create the object with no sensible user data to the client*/
$data = [
'token' => $token,
'user_email' => $user->data->user_email,
'user_nicename' => $user->data->user_nicename,
'user_display_name' => $user->data->display_name,
'user_email' => $user->user_email,
'user_nicename' => $user->user_nicename,
'user_display_name' => $user->display_name,
];

/** Let the user modify the data before send it back */
return apply_filters( 'jwt_auth_token_before_dispatch', $data, $user );
}


/**
* Get the type and token in the request body and generate a JWT after google oauth2 authentication
*
* @param WP_REST_Request $request
*
* @return mixed|WP_Error|null
*/
public function google_authenticate( WP_REST_Request $request ) {
$secret_key = defined( 'JWT_AUTH_SECRET_KEY' ) ? JWT_AUTH_SECRET_KEY : false;
$type = strtolower($request->get_param( 'type' ));
$token = $request->get_param( 'token' );

/** First thing, check the secret key if not exist return an error*/
if ( ! $secret_key ) {
return new WP_Error(
'jwt_auth_bad_config',
__( 'JWT is not configured properly, please contact the admin', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

// Check if token type is valid. i.e: allow type to be either id_token or access_token
if (!in_array($type, ['id_token', 'access_token'])) {
return new WP_Error(
'jwt_google_auth_bad_type',
__( 'Invalid request type. Allowed type: `id_token` or `access_token`', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

if ( $type == "id_token" ) {
$response = wp_remote_get("https://oauth2.googleapis.com/tokeninfo?id_token={$token}");
} else {
$response = wp_remote_get("https://www.googleapis.com/oauth2/v1/userinfo?access_token={$token}");
}

// Check if the response is an error
if (is_wp_error($response)) {
return new WP_Error(
'jwt_google_auth_bad_response',
__( 'Token verification failed', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

$response_data = json_decode(wp_remote_retrieve_body($response), true);

// Check if the response has any error
if (isset($response_data['error_description'])) {
return new WP_Error(
'jwt_google_auth_error_description',
__( 'Invalid token', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

// Check if the response has any error
if (isset($response_data['error'])) {
return new WP_Error(
'jwt_google_auth_error',
__( 'Failed to authenticate. Check the `token` and `type`', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

// Check if the response has email
if (!isset($response_data['email'])) {
return new WP_Error(
'jwt_google_auth_error_email',
__( 'Missing scope. `email` scope is required to authenticate', 'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

// Extract user info from the response
$email = $response_data['email'];
$first_name = isset($response_data['given_name']) ? $response_data['given_name'] : '';
$last_name = isset($response_data['family_name']) ? $response_data['family_name'] : '';
$display_name = isset($response_data['name']) ? $response_data['name'] : '';

// Check if the user already exists
$user = get_user_by('email', $email);
if (!$user) {
// Create a new user if not exists
$user_id = wp_create_user($email, wp_generate_password(), $email);
wp_update_user([
'ID' => $user_id,
'first_name' => $first_name,
'last_name' => $last_name,
'display_name' => $display_name,
]);
$user = get_user_by('id', $user_id);
}

// Check if the user is valid
if ( is_wp_error( $user ) ) {
$error_code = $user->get_error_code();

return new WP_Error(
'[jwt_auth] ' . $error_code,
$user->get_error_message( $error_code ),
[
'status' => 403,
]
);
}

// Create the according Token
$issuedAt = time();
$notBefore = apply_filters( 'jwt_auth_not_before', $issuedAt, $issuedAt );
$expire = apply_filters( 'jwt_auth_expire', $issuedAt + ( DAY_IN_SECONDS * 7 ), $issuedAt );

$token = [
'iss' => get_bloginfo( 'url' ),
'iat' => $issuedAt,
'nbf' => $notBefore,
'exp' => $expire,
'data' => [
'user' => [
'id' => $user->ID,
],
],
];

$algorithm = $this->get_algorithm();
if ( $algorithm === false ) {
return new WP_Error(
'jwt_auth_unsupported_algorithm',
__( 'Algorithm not supported, see https://www.rfc-editor.org/rfc/rfc7518#section-3',
'wp-api-jwt-auth' ),
[
'status' => 403,
]
);
}

$token = JWT::encode(
apply_filters( 'jwt_auth_token_before_sign', $token, $user ),
$secret_key,
$algorithm
);


$data = [
'token' => $token,
'user_email' => $user->user_email,
'user_nicename' => $user->user_nicename,
'user_display_name' => $user->display_name,
];

/** Let the user modify the data before send it back */
Expand Down