1

I want to implement phone number verification using laravel, twilio and authy api.

I followed the tutorials provided on the site https://www.twilio.com/docs/sms but it keeps showing me this error

Unresolvable dependency resolving [Parameter #0 [ $api_key ]] in class Authy\AuthyApi

This is my user's model:

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model implements AuthenticatableContract,
                                    AuthorizableContract,
                                    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'email', 'password', 'country_code', 'phone_number'];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];

    public function fullNumber()
    {
        return '+' . $this->country_code . $this->phone_number;
    }
}

My Controller:

<?php
namespace App\Http\Controllers;

use App\Http\Requests;
use App\User;
use Auth;
use Authy\AuthyApi as AuthyApi;
use DB;
use Hash;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use Illuminate\Support\MessageBag;
use Twilio\Rest\Client;

class UserController extends Controller
{
    /**
     * Store a new user
     *
     * @param  \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function createNewUser(Request $request, AuthyApi $authyApi)
    {
        $this->validate(
            $request, [
                'name' => 'required|string',
                'email' => 'required|unique:users|email',
                'password' => 'required',
                'country_code' => 'required',
                'phone_number' => 'required|numeric'
            ]
        );

        $values = $request->all();
        $values['password'] = Hash::make($values['password']);

        DB::beginTransaction();

        $newUser = new User($values);
        $newUser->save();
        Auth::login($newUser);

        $authyUser = $authyApi->registerUser(
            $newUser->email,
            $newUser->phone_number,
            $newUser->country_code
        );
        if ($authyUser->ok()) {
            $newUser->authy_id = $authyUser->id();
            $newUser->save();
            $request->session()->flash(
                'status',
                "User created successfully"
            );

            $sms = $authyApi->requestSms($newUser->authy_id);
            DB::commit();
            return redirect()->route('user-show-verify');
        } else {
            $errors = $this->getAuthyErrors($authyUser->errors());
            DB::rollback();
            return view('newUser', ['errors' => new MessageBag($errors)]);
        }
    }

    /**
     * This controller function shows the current user status
     *
     * @param Authenticatable $user Current user
     * @return mixed Response view
     */
    public function show(Authenticatable $user)
    {
        return view('showUser', ['user' => $user]);
    }

    /**
     * This controller function handles the submission form
     *
     * @param Request $request Current User Request
     * @param Authenticatable $user Current User
     * @param AuthyApi $authyApi Authy Client
     * @return mixed Response view
     */
    public function verify(Request $request, Authenticatable $user,
                           AuthyApi $authyApi, Client $client)
    {
        $token = $request->input('token');
        $verification = $authyApi->verifyToken($user->authy_id, $token);

        if ($verification->ok()) {
            $user->verified = true;
            $user->save();
            $this->sendSmsNotification($client, $user);

            return redirect()->route('user-index');
        } else {
            $errors = $this->getAuthyErrors($verification->errors());
            return view('verifyUser', ['errors' => new MessageBag($errors)]);
        }
    }

    /**
     * This controller function handles the verification code resent
     *
     * @param Request $request Current User Request
     * @param Authenticatable $user Current User
     * @param AuthyApi $authyApi Authy Client
     * @return mixed Response view
     */
    public function verifyResend(Request $request, Authenticatable $user,
                                 AuthyApi $authyApi)
    {
        $sms = $authyApi->requestSms($user->authy_id);

        if ($sms->ok()) {
            $request->session()->flash(
                'status',
                'Verification code re-sent'
            );
            return redirect()->route('user-show-verify');
        } else {
            $errors = $this->getAuthyErrors($sms->errors());
            return view('verifyUser', ['errors' => new MessageBag($errors)]);
        }
    }

    private function getAuthyErrors($authyErrors)
    {
        $errors = [];
        foreach ($authyErrors as $field => $message) {
            array_push($errors, $field . ': ' . $message);
        }
        return $errors;
    }

    private function sendSmsNotification($client, $user)
    {
        $twilioNumber = config('services.twilio')['number'] or die(
            "TWILIO_NUMBER is not set in the environment"
        );
        $messageBody = 'You did it! Signup complete :)';

        $client->messages->create(
            $user->fullNumber(),    // Phone number which receives the message
            [
                "from" => $twilioNumber, // From a Twilio number in your account
                "body" => $messageBody
            ]
        );
    }
}

the Migration file:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email',191)->unique();
            $table->string('password', 60);
            $table->string('phone_number');
            $table->string('country_code');
            $table->string('authy_id')->nullable();
            $table->boolean('verified')->default(false);
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Providers

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Services_Twilio;
use Twilio\Rest\Client;

class TwilioRestClientProvider extends ServiceProvider
{
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            $accountSid = config('services.twilio')['accountSid']
                or die("TWILIO_ACCOUNT_SID is not set in the environment");
            $authToken = config('services.twilio')['authToken']
                or die("TWILIO_AUTH_TOKEN is not set in the environment");

            return new Client($accountSid, $authToken);
        });
    }
}

<?php
namespace App\Providers;

use Authy\AuthyApi as AuthyApi;
use Illuminate\Support\ServiceProvider;

class AuthyApiProvider extends ServiceProvider
{
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(AuthyApi::class, function ($app) {
            $authyKey = getenv('AUTHY_API_KEY') or die(
                "You must specify your api key for Authy. " .
                "Visit https://dashboard.authy.com/"
            );
            return new AuthyApi($authyKey);
        });
    }
}


the view file

@extends('layouts.master')

@section('title')
    Sign Up
@endsection

@section('content')
    <div class="container">
      <h1>We're going to be *BEST* friends</h1>
      <p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>

      {!! Form::open(['url' => route('user-create')]) !!}
          <div class="form-group">
              {!! Form::label('name') !!}
              {!! Form::text('name', '', ['class' => 'form-control', 'placeholder' => 'Zingelbert Bembledack']) !!}
          </div>
          <div class="form-group">
              {!! Form::label('email') !!}
              {!! Form::text('email', '', ['class' => 'form-control', 'placeholder' => 'me@mydomain.com']) !!}
          </div>
          <div class="form-group">
              {!! Form::label('password') !!}
              {!! Form::password('password', ['class' => 'form-control']) !!}
          </div>
          <div class="form-group">
              {!! Form::label('country_code', 'Country Code') !!}
              {!! Form::text('country_code', '', ['class' => 'form-control', 'id' => 'authy-countries']) !!}
          </div>
          <div class="form-group">
              {!! Form::label('phone_number', 'Phone number') !!}
              {!! Form::text('phone_number', '', ['class' => 'form-control', 'id' => 'authy-cellphone']) !!}
          </div>
          <div class="form-group">
              <button type="submit" class="btn btn-primary">Sign up</button>
          </div>
      {!! Form::close() !!}
    </div>
@endsection

The environment file

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=vmsdb
DB_USERNAME=root
DB_PASSWORD=



# Twilio API credentials
# Found at https://www.twilio.com/user/account/settings
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=

# Twilio phone number
# Purchase one at https://www.twilio.com/user/account/phone-numbers
TWILIO_NUMBER=

# Authy Credentials
AUTHY_API_KEY=




BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

But keeps showing the error:

Unresolvable dependency resolving [Parameter #0 [ <required> $api_key ]] in class Authy\AuthyApi

And I've required both authy and twilio from composer package but its still showing the same error please I need help. Thanks

Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
Rimsy Boyi
  • 13
  • 1
  • 4
  • Hey Rimsy! Twilio Developer Evangelist here - Margaret's answer below should help with your credential issue. Also wanted to let you know that we're releasing a new version of the Verify API today that uses the Twilio PHP helper library which is better maintained than the old Authy one. Check it out https://www.twilio.com/docs/verify/api-beta and let me know if you have any questions! krobinson@twilio.com – Kelley Robinson Apr 02 '19 at 15:10

1 Answers1

1

Please, remove your credentials when sharing your project!

It looks like you're attempting to use getenv() to pull your info from your .env file, but that's not the Laravel way of doing this and that might be causing issues (https://laracasts.com/discuss/channels/laravel/cant-get-getenvkey?page=1).

I recommend setting up these values in config/services.php and then fetching them using Laravel's config() method (https://laravel.com/docs/5.8/configuration).

So your config/services.php would look something like:

return [
    'authy' => [
        'key' => env('AUTHY_API_KEY'),
    ],

];

and then fetching the api key would look something like:

config('services.authy.key');
Margaret
  • 98
  • 8
  • Oh ok let met try that out and see. Please just to clarify, I should add the return [...] to the config/services.php then instead of using ```getenv('AUTHY_API_KEY')``` in the provider class I should add this ```config('services.authy.key');``` instead right? – Rimsy Boyi Apr 02 '19 at 22:49
  • $authyApi = new AuthyApi(config('services.authy.key')); – mikebertiean Apr 13 '19 at 15:31