scrivito
Version:
Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.
90 lines (75 loc) • 2.5 kB
text/typescript
import { AuthorizationProvider } from 'scrivito_sdk/client';
import { VisitorSession, cmsRestApi } from 'scrivito_sdk/client/cms_rest_api';
import { PublicAuthentication } from 'scrivito_sdk/client/public_authentication';
import {
Deferred,
ScrivitoError,
randomId,
throwNextTick,
} from 'scrivito_sdk/common';
/**
* The VisitorAuthenticationProvider is responsible to provide the visitor
* session to authenticate backend requests for a Scrivito configured with
* visitor authentication.
*
* The visitor session is retrieved from backend using the id token that
* the provider has received. Backend requests are delayed until the first
* session response arrives.
*
* Responses of visitor session authenticated backend requests are monitored
* if they indicate an expired session, and retried either with a fresh
* visitor session or without authentication.
*/
export class VisitorAuthenticationProvider implements AuthorizationProvider {
private readonly sessionId = randomId();
private idToken = new Deferred<string>();
private sessionRequest: Promise<VisitorSession>;
private state = 'waiting for token';
constructor() {
this.sessionRequest = this.fetchSession();
}
setToken(token: string) {
if (!this.idToken.isPending()) {
this.idToken = new Deferred();
this.renewSession();
}
this.idToken.resolve(token);
this.state = `active - token: ${token.substr(0, 3)}...`;
}
currentState(): string {
return this.state;
}
async authorize(
request: (authorization: string | undefined) => Promise<Response>
): Promise<Response> {
const sessionRequest = this.sessionRequest;
let session: VisitorSession;
try {
session = await sessionRequest;
} catch {
return PublicAuthentication.authorize(request);
}
const response = await request(`Session ${session.token}`);
if (response.status === 401) {
if (this.sessionRequest === sessionRequest) this.renewSession();
return this.authorize(request);
}
return response;
}
private renewSession() {
this.sessionRequest = this.fetchSession();
}
private async fetchSession() {
try {
const token = await this.idToken;
return await cmsRestApi.requestVisitorSession(this.sessionId, token);
} catch (error) {
throwNextTick(
new ScrivitoError(
`Failed to establish visitor session: ${(error as Error).message}`
)
);
throw error;
}
}
}