Public API
What this package exposes, as it is built today. Everything here is a promise to consumers: adding to it is a minor release, changing or removing it is a major one.
This page describes the code on main. A pull request that changes the surface changes this page in the same change.
Namespace layout
src/
├── LaravelAutentiqueServiceProvider.php # merges the config, binds the contract
├── AutentiqueManager.php # the Autentique implementation
├── Contracts/ # Autentique, GraphQLClient, FileSource
├── Api/ # one class per area of the API: Account, Corporate, Documents, Folders, OAuth, Organizations, PendingDocument, Signers
├── Commands/ # CheckCommand, SchemaCommand
├── Events/ # AutentiqueWebhookReceived
├── Facades/Autentique.php
├── Data/ # value objects returned: Document, Signature, User, …
│ └── Input/ # value objects sent: NewDocument, Signer, Position, …
├── Enums/ # every closed set of API values, and ErrorCode
├── Io/ # PathFile, UploadedFileSource, DiskFile
├── Exceptions/ # AutentiqueException and what extends it
├── GraphQL/ # Client, ResponseParser, Operation, Endpoint, OperationLoader
└── Resources/graphql/ # one .graphql file per operation
lang/{en,pt_BR}/errors.php # the text of every ErrorCodeThe root namespace LSNepomuceno\LaravelAutentique is fixed; renaming it would be a gratuitous break.
The facade, and the contract behind it
Contracts\Autentique, resolved from the container as a singleton or reached through the Autentique facade, which is auto discovered.
| Method | Returns | Notes |
|---|---|---|
account() | Api\Account | me() returns Data\User |
documents() | Api\Documents | create(), find(), update(), block() return Data\Document; list() returns Data\Page<Document>; delete(), sign(), transfer(), moveToFolder() return bool |
signers() | Api\Signers | add(), approveBiometric(), rejectBiometric() return Data\Signature; link() returns Data\Link; remove(), resend() return bool |
folders() | Api\Folders | find(), create(), rename(), share(), changeRole(), shareByLink(), stopSharingByLink(), removeLinkPassword() return Data\Folder; list() returns Data\Page<Folder>; documents() returns Data\Page<Document>; delete() returns bool |
organizations() | Api\Organizations | current() returns Data\Organization with groups; list() returns list<Organization>; emailTemplates() returns Data\Page<EmailTemplate> |
corporate() | Api\Corporate | the Corporate endpoint: child organizations, members, login codes, webhook endpoints, custom plans, API usage |
oauth() | Api\OAuth | begin() returns Data\Authorization; callback(), exchange(), refresh() return Data\OAuthTokens; OAuth::challenge() is the S256 challenge |
withToken($token) | Contracts\Autentique | the whole API sending another token |
newDocument($name) | Api\PendingDocument | the builder; send() returns Data\Document |
fromPath($path, ?$name), fromUpload($file, ?$name), fromDisk($disk, $path, ?$name) | Contracts\FileSource | Laravel only: uploads and disks stream |
query($graphql, $variables) | array<string, mixed>, the response's data | the escape hatch; values as variables, the document is the caller's |
Every method must appear in the README, which tests/Project/ArchTest.php checks, and in the facade's @method docblock.
The transport
Contracts\GraphQLClient is bound to GraphQL\Client, the only class that reaches the network (invariant 1), the OAuth token endpoint included. It is a contract so the fake can stand in for it; an application may bind its own, at the cost of Http::fake() no longer reaching it.
Contracts\FileSource is what an upload reads: a name and contents, a string or a stream.
The contract is bound rather than the class, so an application can bind its own implementation in a service provider.
Operations
GraphQL\Operation names every operation the package sends, one case per file under src/Resources/graphql/. It is public because tests and the fake name operations by it. Adding a case is a minor release; removing or renaming one is a major release.
The selection of fields inside each file is not itself public: what is public is the value object built from it (0008).
Value objects
Every answer is a final readonly class under Data\, built from the fields its operation selects (0008). Property names are camel case ($hasPremiumFeatures for has_premium_features), dates are CarbonImmutable, and a field the API may omit is nullable.
| Class | Built from |
|---|---|
Data\User | me |
Data\Subscription, Data\Organization, Data\Group | nested in the above, and in organization |
Data\Document | createDocument and every operation returning a document |
Data\Page<T> | every listing; countable, iterable, and filter() keeps Autentique's counts |
Data\Folder, Data\FolderSummary, Data\FolderShare | the folder operations |
Data\EmailTemplate | emailTemplates |
Data\ChildOrganization, Data\OrganizationMember, Data\OrganizationPlan, Data\CorporatePlan, Data\ApiUsage, Data\ApiUsageItems, Data\WebhookEndpoint | the Corporate operations. OrganizationMember::$apiToken and WebhookEndpoint::$secret are credentials |
Data\Authorization, Data\OAuthTokens | the OAuth flow; both carry credentials |
Data\WebhookEvent | a webhook's body; the resource stays the array Autentique sent |
Data\Signature, Data\Link, Data\Files, Data\Event, Data\Geolocation, Data\EmailEvents, Data\SignaturePosition, Data\Verification | nested in a document |
An enum value the API returns and the package does not know yet becomes null rather than an exception, so a new value Autentique adds breaks nothing.
Inputs
What is sent is a final readonly class under Data\Input\: NewDocument, DocumentChanges, Share, Signer, PrefilledFields, NewChildOrganization, ChildOrganizationChanges, NewMember, NewSubscriptionPlan, Position, SecurityVerification, Locale, DocumentConfig, Expiration. Each refuses, with InvalidInput, a value Autentique documents it would refuse or silently change. toArray() returns what is sent, with every unset option left out so Autentique's default applies.
Api\PendingDocument is the one mutable class: a builder, whose methods return the same instance.
Adding a property is a minor release; removing one, or making a nullable one required, is a major release.
Support\Payload is how they read an answer. It is not public.
Exceptions
Everything the package throws extends Exceptions\AutentiqueException, which is abstract.
| Exception | When |
|---|---|
RequestFailed (abstract) | base of the nine below; carries $operation, $status, $requestId, $errors |
Unauthenticated | HTTP 401, or the code unauthorized |
InsufficientScope | Unauthorized, capitalised, with 200: an OAuth token without the scope |
OAuthFailed | an OAuth step failed; carries $error |
RateLimited | HTTP 429 after the retries; carries $retryAfter |
ValidationFailed | message: "validation"; violations(), messages() |
NotFound | a *_not_found code, or a … not found message |
ResendThrottled | too_many_resent_emails on resendSignatures; wraps the GraphQLError |
GraphQLError | any other error, or no data |
TransportFailed | the connection failed, or the answer was not GraphQL |
MissingToken | no token configured, nothing sent |
InvalidOperation | an operation file is missing or spreads a fragment no file defines. A defect in the package, which the suite exists to prevent |
UnexpectedResponse | an answer without a field the package requires. The API and the package disagree about the schema |
InvalidInput | a value refused before sending |
MissingWebhookSecret | a webhook arrived with no secret to verify it |
MissingOAuthCredentials | OAuth used without its configuration |
Enums\ErrorCode lists every code Autentique documents; Data\ApiError and Data\Violation carry what arrived. Adding a case is a minor release.
Webhooks
| Class | |
|---|---|
Webhooks\VerifyAutentiqueSignature | middleware; 401 on a bad signature, MissingWebhookSecret without a secret |
Webhooks\SignatureVerifier | verify($body, $signature, $secret), sign($body, $secret) |
Webhooks\WebhookController | the route's controller; public so an application can reuse it on its own route |
Events\AutentiqueWebhookReceived | dispatched with a Data\WebhookEvent |
Enums\WebhookEventType | the seventeen types |
The route autentique.webhook, registered only when autentique.webhooks.path is set. Its answers are 200 {"received": true}, 200 {"received": true, "duplicate": true} for a dropped repeat, 400 for a signed body that is not an event, 401 for a bad signature.
Testing
Autentique::fake() returns Testing\AutentiqueFake, installed in place of Contracts\GraphQLClient. Its answers are shaped from what was sent; respond(), fail() and respondToQuery() override them. Its assertions are assertDocumentSent(), assertDocumentSentTimes(), assertNoDocumentSent(), assertSignerAdded(), assertResent(), assertSent(), assertNotSent(), assertSentTimes() and assertNothingSent(), and sent() returns every Testing\SentOperation.
Testing\FakeWebhook::make() builds a signed webhook body.
src/Testing uses PHPUnit's assertions, as Laravel's own fakes do, and runs only inside a test suite, where PHPUnit is installed.
Commands
| Command | Exit codes |
|---|---|
autentique:check | 0 token accepted, 1 otherwise |
autentique:schema {--output=} | 0 written, 1 refused |
Their names and exit codes are public: a pipeline calls them.
Configuration
config/autentique.php, publishable with the autentique-config tag. Every key is a scalar (invariant 4).
| Key | Environment | Default |
|---|---|---|
token | AUTENTIQUE_TOKEN | none |
url | AUTENTIQUE_URL | https://api.autentique.com.br/v2/graphql |
corporate_url | AUTENTIQUE_CORPORATE_URL | https://api.autentique.com.br/v2/graphql/corporate |
sandbox | AUTENTIQUE_SANDBOX | false |
timeout | AUTENTIQUE_TIMEOUT | 30 seconds |
retry.times | AUTENTIQUE_RETRY_TIMES | 2 |
retry.sleep | AUTENTIQUE_RETRY_SLEEP | 1000 milliseconds |
webhooks.secret | AUTENTIQUE_WEBHOOK_SECRET | none |
webhooks.path | AUTENTIQUE_WEBHOOK_PATH | none, no route |
webhooks.middleware | [] | |
webhooks.deduplicate | AUTENTIQUE_WEBHOOK_DEDUPLICATE | none, off |
webhooks.cache_store | AUTENTIQUE_WEBHOOK_CACHE_STORE | the default store |
oauth.client_id, oauth.client_secret, oauth.redirect_uri | AUTENTIQUE_OAUTH_* | none |
oauth.url | AUTENTIQUE_OAUTH_URL | https://api.autentique.com.br/oauth |
Adding a key is a minor release. Removing or renaming one is a major release, because an application's published config file keeps the old name.
Experimental
Promised by nothing above until it has run against Autentique itself:
Api\Corporate, the operations undersrc/Resources/graphql/corporate/, and the value objects, inputs and enums only it uses;Api\OAuth,Data\Authorization,Data\OAuthTokens,Enums\OAuthScope, and howExceptions\InsufficientScopeis recognised.
The Corporate endpoint needs an account on the Corporate plan, and OAuth a registered application; the maintainer's account had neither for 1.0.0, so the Corporate schema is still assembled from the documentation. The first run against the standard endpoint changed a signature and five enums, and the same may happen here. Until that run, these change in a minor release, recorded in the changelog and in UPGRADE.md, and this section shrinks as each is verified (#48).
Autentique::corporate(), Autentique::oauth() and Autentique::withToken() themselves are stable.
What is not public
- The private methods of the manager and the provider.
- Anything under
tests/, which never ships.