Skip to main content
Documentation & User Guides | Fotoware

Authorization of single-page JavaScript web apps (SPA) without back end

 

A single-page application (SPA) in this context means a pure front-end web application that does not communicate with a back-end, other than for loading static resources, such as HTML, JavaScript, etc.). Note that if a back-end is available, and if it is possible for a back-end to receive the OAuth callback, then we recommend using the approach for web applications and APIs instead, as it provides additional security, even if the application itself does not communicate with the back-end. If a SPA receives the callback directly (without using a back-end), then it is effectively a "native" application (a public client) that runs in a web browser.There are two approaches that can be used for SPAs without a back-end:

  1. Authorization code grant with cross-origin request sharing (CORS) - this approach is recommended if available.
  2. Implicit grant - this approach is deprecated.

Note: CORS is currently only available for FotoWeb On-Premises and requires manual setup in the web server (IIS). For more information, see Enabling CORS in FotoWare.

Note: If FotoWeb and the integration are hosted on the same domain, then it is not necessary to set up CORS.

Note: We strongly discourage using browser extensions or other means to circumvent or disable CORS, as this would be a security risk.

If CORS is has been set up and is available, then the protocol for authorization is the same as for native applications, except the OAuth callback is handled by the front-end, and the token request is sent from JavaScript code rather than a back-end. The remainder of this article describes implicit grant.

Note:

  • Refresh tokens are not available when using implicit grant.
  • CORS it not required when using implicit grant.
  • Implicit grant is deprecated in the OAuth 2.1 standard.

Application registration

  1. From the Tools menu (cogwheel icon) go to Site Configuration Integrations > Applications.
  2. Select Add application.

Application_registration_-_without_back_end.png

User consent

A custom text can be added to the user consent dialog, in Markdown format. It is also possible to include a URI to a privacy policy web page that governs the use of the system.

This information will be displayed in the consent dialog when the application requests access to the site so the user can review it before proceeding.

Protocol flow

The client opens a browser window to the following URL (line-breaks are added for readability. All parameter values must be URL-encoded):

https://myfotowebserver.com/fotoweb/oauth2/authorize?
    response_type=token&
    client_id=CLIENT_ID&
    redirect_uri=REDIRECT_URI&
    state=STATE

where

Parameter

Description

response_type Mandatory. Must always be token.
client_id Mandatory. The unique ID of the client, which was obtained during client registration.
redirect_uri

The redirection endpoint URI of the client.

If given, it must match with one of the redirection endpoint URIs registered for the client.

Optional if the application only has one registration endpoint.

Mandatory if the application has more than one registration endpoint.

state

Mandatory: This should be a unique, cryptographically safe random string.

This request may result in the user being shown a login prompt for FotoWeb.

On success, the server responds by redirecting the user to the redirection endpoint URI of the client. This is always one of the redirection endpoint registered for the client and, if given, the redirection URI passed in the request as redirect_uri.

Parameters are added to the fragment part of the redirection URI as follows (line-breaks added for readability. All parameter values are URL-encoded):

https://myapplication.com/oauth2/callback#
    access_token=ACCESS_TOKEN&
    token_type=bearer&
    expires_in=EXPIRES_IN_SECONDS
    state=STATE

where

Parameter

Description

access_token The access token that is used to authorize requests to the FotoWeb API
token_type This is always bearer.
expires_in Number of seconds after which the token is expected to expire.
state

This is always identical to the string passed to the request in the state parameter.

The client should check that the returned string is identical to the sent string.

This is to protect against cross-site request forgery (CSRF).

The application can obtain the access token by parsing the fragment part of the redirection URL.

The server will not issue a refresh token if implicit grant is used. When the access token has expired, the only way to obtain a new access token is to repeat authorization.

Implementation in JavaScript

The following JavaScript functions can be used to implement OAuth 2.0 in a single-page application:

function createState()
{
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_~.";
    for (var i = 0; i < 16; ++i)
        text += possible.charAt(Math.floor(Math.random() * possible.length));


    return text;
}


function requestAuthorization(tenantURL, clientID, redirectURI)
{
    var state = createState();
    sessionStorage.setItem('state', state);


    window.location = tenantURL + "/fotoweb/oauth2/authorize?" +
        "response_type=token&" +
        "client_id=" + clientID + "&" +
        "redirect_uri=" + encodeURIComponent(redirectURI) + "&" +
        "state=" + encodeURIComponent(state);
}


function getAccessToken()
{
    var state = sessionStorage.getItem('state');
    if (state === null) return null;


    var params = window.location.hash.substring(1).split('&');
    var token = null;
    var stateValid = false;
    for (var i = 0; i < params.length; ++i)
    {
        var pair = params[i].split('=');
        if (decodeURIComponent(pair[0]) === 'access_token')
        {
            token = decodeURIComponent(pair[1]);
        }
        else if (decodeURIComponent(pair[0]) === 'state') {
            if (state === decodeURIComponent(pair[1]))
                stateValid = true;
            else
                alert("Invalid state! Someone is trying to mess with you!")
        }
    }


    if (stateValid)
        return token;


    return null;
}

The requestAuthorization function redirects the user to the authorization endpoint of FotoWeb. It may be called, for example, when the user clicks a "Log in with FotoWeb" button. The parameters are as follows:

The getAccessToken function reads the access token from the fragment part of the URL after authorization was successful.

This implementation validates the OAuth 2.0 state parameter by creating a random value before the authorization process and passing it to the getAccessToken function using session storage.

This prevents cross-site request forgery (CSRF) and embedding the app into other apps (mash-ups) by ensuring that the app only accepts access tokens it has itself requested.

Any additional parameters to the application may be passed through the authorization process in session storage.

What's next? 

To learn how to use OAuth acces tokens in your configuration, see Using application access tokens for OAuth 2.0 authorization.