Table of Contents

Class PortalAuthenticationProvider

Namespace
VpnHood.AppLib.Portal
Assembly
VpnHood.AppLib.Portal.dll

Signs in against the Portal API (POST /auth/sessions with a provider id token) and holds the opaque session token, persisted like the Store package's api key. It hands that token out on request; attaching it to a call is the caller's business, so nothing here owns a client anyone else uses.

public class PortalAuthenticationProvider : IAuthenticationProvider, IDisposable
Inheritance
PortalAuthenticationProvider
Implements
Inherited Members

Constructors

PortalAuthenticationProvider(Storage, Uri, string, IReadOnlyList<IAuthenticationExternalProvider>, IRestoreCredentialProvider?, bool)

Initializes a new instance of the PortalAuthenticationProvider class.

public PortalAuthenticationProvider(Storage storage, Uri portalBaseUrl, string packageName, IReadOnlyList<IAuthenticationExternalProvider> authenticationExternalProviders, IRestoreCredentialProvider? restoreCredentialProvider = null, bool ignoreSslVerification = false)

Parameters

storage Storage

The app's storage, whose account folder keeps the session and the mark of the zero-tap restore's final answer. It must be one no device backup or transfer copies: a copied mark skips the zero-tap restore on the new device.

portalBaseUrl Uri

The portal's address.

packageName string

The app's package name, which the portal knows the app by.

authenticationExternalProviders IReadOnlyList<IAuthenticationExternalProvider>

The identity providers' own sign-ins, as Google's or Apple's; this provider disposes them.

restoreCredentialProvider IRestoreCredentialProvider

The device's restore credential, for the zero-tap restore of a sign-in, or null; this provider disposes it.

ignoreSslVerification bool

true to accept any server certificate, as a development portal's.

Exceptions

ArgumentException

Two of authenticationExternalProviders declare the same ID, or one declares Password, the portal's own.

Properties

ProviderIds

Gets the IDs of the sign-in methods the app offers, the ones ProviderId may name; the well-known ones are in AuthProviders.

public IReadOnlyList<string> ProviderIds { get; }

Property Value

IReadOnlyList<string>

Remarks

They are the external providers' own IDs, in their order, then Password, the portal's own email and password sign-in; an identity provider's ID reaches the portal as it is.

UserId

The signed-in account's id, or null. Ambient and cheap: it is read straight from the persisted session, so a device signed in yesterday knows it without any call.

public string? UserId { get; }

Property Value

string

Methods

Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

Remarks

It disposes the identity providers, the restore credential's provider and its HTTP client; a second call does nothing.

GetAccessToken(CancellationToken)

The credential for the current session, or null when nobody is signed in; an anonymous call simply never asks for one. Async, and hence not a property beside UserId, as a provider may have to work for it: the portal's tries a zero-tap restore of the sign-in where nobody is signed in. The portal never renews it: its sessions have no time limit and last until the backend refuses them (InvalidateAccessToken(string)).

public Task<string?> GetAccessToken(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task<string>

A task whose result is the credential, or null where nobody is signed in.

Remarks

It gives the portal's session token. Where nobody is signed in, it first tries a zero-tap restore of the sign-in, at most once per run, and only with a restore credential provider, a window, and no final answer recorded in an earlier run; it gives null where that fails, a cancel included. Sign-in itself must not go through here: its 401 means "wrong credentials", not "dead session".

GetPasswordResetUrl(CancellationToken)

The page of the human account website behind this provider where a person recovers a password, or null when there is none. Asked when the password sign-in form opens, which offers it as its escape hatch only when a page comes back — never as an API endpoint.

public Task<Uri?> GetPasswordResetUrl(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task<Uri>

A task whose result is the page, or null where there is none.

Remarks

The portal tells it, for a request without a session.

Exceptions

ApiException

The account backend refused the request.

OperationCanceledException

cancellationToken was canceled.

InvalidateAccessToken(string)

The backend refused this token: the session is over. The token is passed back so a stale in-flight refusal cannot end a session that has meanwhile been replaced by a newer sign-in.

public void InvalidateAccessToken(string accessToken)

Parameters

accessToken string

The token the backend refused.

Remarks

The portal answered 401: it does not know this session any more. There is no refresh token to fall back on, so the only honest local state is signed-out — the account was deleted, or its sessions revoked, somewhere else. Dropping the session here is what stops this device from showing a person the server has already forgotten.

The external identity provider is deliberately left signed in: revoking it needs a UI context no HTTP response handler has, and the next deliberate sign-in re-establishes everything anyway.

A session with another token than the refused one is kept.

SignIn(IUiContext?, SignInOptions, CancellationToken)

Signs the person in, or answers the second step of a sign-in that asked for one.

public Task<SignInResult> SignIn(IUiContext? uiContext, SignInOptions signInOptions, CancellationToken cancellationToken)

Parameters

uiContext IUiContext

The window, or null where none is open, as in the desktop service: the password sign-in needs none.

signInOptions SignInOptions

The sign-in method, with its credentials or the second step's code.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task<SignInResult>

A task whose result is what the sign-in accomplished.

Remarks

The password sign-in goes to the portal itself. Another method asks its identity provider for an ID token, never silently, and hands it to the portal. A sign-in that passes also tries to register the device's restore credential, which does not fail the sign-in.

Exceptions

UiContextNotAvailableException

uiContext is null, and the method shows a sheet, as Google's and Apple's do.

NotSupportedException

The method is not one of ProviderIds, or the account's second step is of a kind the app cannot answer.

ArgumentException

The password sign-in's first step lacks the email address or the password.

InvalidOperationException

A second step's code came with no sign-in waiting for one.

AuthenticationException

The identity provider gave no ID token, as Google's where the device has no Google account.

ApiException

The account backend refused the request.

OperationCanceledException

The person canceled the sign-in, or cancellationToken was canceled.

InvalidOperationException

A second step's code came with no sign-in waiting for one, or the portal's answer carries no session token or user ID.

SignOut(IUiContext?, CancellationToken)

Signs the person out.

public Task SignOut(IUiContext? uiContext, CancellationToken cancellationToken)

Parameters

uiContext IUiContext

The window, or null where none is open.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

The session ends on the device either way; what only a window can clear on the device is left where none is open.