Authentication

Authenticating an agent was briefly covered in the Getting Started page. This page we’ll provide more information about authentication in general.

Logging in

As discussed before, an agent can be authenticated on a context by using the authenticate method in the Auth service, e.g.:

// ... imports

let carbon;

// ... platform context creation

carbon.auth.authenticate( "your@email.com", "YouRP455word" ).then(
    ( token ) => {
        console.log( carbon.auth.authenticatedAgent ); // Yourself!
    }
);
// ... additional imports
import Carbon from "carbonldp/Carbon";
import * as Token from "carbonldp/Auth/Token";

let carbon:Carbon;

// ... platform context creation

carbon.auth.authenticate( "your@email.com", "YouRP455word" ).then(
    ( token:Token.Class ) => {
        console.log( carbon.auth.authenticatedAgent ); // Yourself!
    }
);
var carbon;

// ... platform context creation

carbon.auth.authenticate( "your@email.com", "YouRP455word" ).then(
    function( token ) {
        console.log( carbon.auth.authenticatedAgent ); // Yourself!
    }
);

This method will retrieve a JWT token that represents your authentication with the platform, and store it inside of the context you called the method in.

In the previous example the method was called using the Auth service of the platform context. This means that all requests made by any service of that context will use that authentication. Also, any context derived from it will inherit the authentication and use it on all requests unless the authentication is overwritten on that context. E.g.:

// ... imports

let carbon;

// ... platform context creation

let appContext;

carbon.auth.authenticate( "agent1@example.com", "SomePassword" ).then(
    ( token ) => {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1

        return carbon.apps.getContext( "your-app-slug/" );
    }
).then(
    ( _appContext ) => {
        appContext = _appContext;

        console.log( appContext.auth.authenticatedAgent ); // Agent 1

        // Override authentication on appContext
        return appContext.auth.authenticate( "agent2@example.com", "SomeOtherPassword" );
    }
).then(
    ( token ) => {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1
        console.log( appContext.auth.authenticatedAgent ); // Agent 2
    }
);
// ... additional imports
import Carbon from "carbonldp/Carbon";
import * as App from "carbonldp/App";
import * as Token from "carbonldp/Auth/Token";

let carbon:Carbon;

// ... platform context creation

let appContext:App.Context;

carbon.auth.authenticate( "agent1@example.com", "SomePassword" ).then(
    ( token:Token.Class ) => {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1

        return carbon.apps.getContext( "your-app-slug/" );
    }
).then(
    ( _appContext:App.Context.Class ) => {
        appContext = _appContext;

        console.log( appContext.auth.authenticatedAgent ); // Agent 1

        // Override authentication on appContext
        return appContext.auth.authenticate( "agent2@example.com", "SomeOtherPassword" );
    }
).then(
    ( token:Token.Class ) => {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1
        console.log( appContext.auth.authenticatedAgent ); // Agent 2
    }
);
var carbon;

// ... platform context creation

var appContext:App.Context;

carbon.auth.authenticate( "agent1@example.com", "SomePassword" ).then(
    function( token ) {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1

        return carbon.apps.getContext( "your-app-slug/" );
    }
).then(
    function( _appContext ) {
        appContext = _appContext;

        console.log( appContext.auth.authenticatedAgent ); // Agent 1

        // Override authentication on appContext
        return appContext.auth.authenticate( "agent2@example.com", "SomeOtherPassword" );
    }
).then(
    function( token:Token.Class ) {
        console.log( carbon.auth.authenticatedAgent ); // Agent 1
        console.log( appContext.auth.authenticatedAgent ); // Agent 2
    }
);

Keeping authentication across page loads

As long as your application can hold a reference of the context you are working on, you’ll be able to maintain your user’s authentication. But what happens if you want to keep your users authenticated across page loads?

The answer lies on the JWT the authenticate method returns. This token can be saved to later use it to authenticate the agent again with the authenticateUsing method in the Auth service.

Here’s an example on how to do that using cookies, but local storage or any other persistence method could be used:

// ... imports

let appContext:App.Context;

// ... app context retrieval

function authenticate( username, password, rememberMe ) {
    return appContext.authenticate( username, password ).then(
        ( token ) => {
            if( rememberMe ) {
                let cookieValue = JSON.stringify( {
                    expirationTime: token.expirationTime,
                    key: token.key
                } );
                setCookie( "auth-token", cookieValue, 3 );
            }
        }
    );
}

// When starting the application this method could be called to try to authenticate the agent and if not present him with a login form
function reAuthenticate() {
    let authCookie = getCookie( "auth-token" );
    if( authCookie === null ) return Promise.reject( "There's no saved token to authenticate with" );

    let savedToken;
    try {
        savedToken = JSON.parse( authCookie );
    } catch( error ) {
        deleteCookie( "auth-token" );
        return Promise.reject( "The saved token couldn't be parsed" );
    }

    return appContext.authenticateUsing( "TOKEN", savedToken ).catch(
        ( error ) => {
            if( error instanceof Errors.IllegalArgumentError || error instanceof HTTP.Errors.UnauthorizedError ) {
                // Invalid token
                deleteCookie( "auth-token" );
                return Promise.reject( "The saved token was invalid" );
            } else return Promise.reject( error );
        }
    );
}

// Simple function to retrieve a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function getCookie( name ) {
    let cookies[] = document.cookie.split( ";" );
    for( let cookie in cookies ) {
        cookie = cookie.trim();
        if( cookie.indexOf( `${name}=` ) === 0 ) return c.substring( `${name}=`.length, cookie.length );
    }
    return null;
}
// Simple function to set a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function setCookie( name, value, days ) {
    let expires = "";
    if( days ) {
        let date = new Date();
        date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
        expires = `; expires=${ date.toUTCString() }`;
    }
    document.cookie = `${ name }=${ value }${ expires }; path=/`;
}
// Simple function to delete a cookie using vanilla JavaScript. jQuery $.removeCookie method could be used instead
function deleteCookie( name ) {
    setCookie( name, "", -1 );
}
// ... additional imports
import * as App from "carbonldp/App";
import * as Errors from "carbonldp/Errors";
import * as HTTP from "carbonldp/HTTP";
import * as Token from "carbonldp/Auth/Token";

let appContext:App.Context;

// ... app context retrieval

function authenticate( username:string, password:string, rememberMe:boolean ):Promise<Token.Class> {
    return appContext.authenticate( username, password ).then(
        ( token:Token.Class ) => {
            if( rememberMe ) {
                let cookieValue:string = JSON.stringify( {
                    expirationTime: token.expirationTime,
                    key: token.key
                } );
                setCookie( "auth-token", cookieValue, 3 );
            }
        }
    );
}

// When starting the application this method could be called to try to authenticate the agent and if not present him with a login form
function reAuthenticate():Promise<Token.Class> {
    let authCookie:string | null = getCookie( "auth-token" );
    if( authCookie === null ) return Promise.reject( "There's no saved token to authenticate with" );

    let savedToken:{ expirationTime:Date, key:string };
    try {
        savedToken = JSON.parse( authCookie );
    } catch( error ) {
        deleteCookie( "auth-token" );
        return Promise.reject( "The saved token couldn't be parsed" );
    }

    return appContext.authenticateUsing( "TOKEN", savedToken ).catch(
        ( error ) => {
            if( error instanceof Errors.IllegalArgumentError || error instanceof HTTP.Errors.UnauthorizedError ) {
                // Invalid token
                deleteCookie( "auth-token" );
                return Promise.reject( "The saved token was invalid" );
            } else return Promise.reject( error );
        }
    );
}

// Simple function to retrieve a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function getCookie( name:string ):string | null {
    let cookies:string[] = document.cookie.split( ";" );
    for( let cookie in cookies ) {
        cookie = cookie.trim();
        if( cookie.indexOf( `${name}=` ) === 0 ) return c.substring( `${name}=`.length, cookie.length );
    }
    return null;
}
// Simple function to set a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function setCookie( name:string, value:string, days:number ):void {
    let expires:string = "";
    if( days ) {
        let date:Date = new Date();
        date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
        expires = `; expires=${ date.toUTCString() }`;
    }
    document.cookie = `${ name }=${ value }${ expires }; path=/`;
}
// Simple function to delete a cookie using vanilla JavaScript. jQuery $.removeCookie method could be used instead
function deleteCookie( name:string ):void {
    setCookie( name, "", -1 );
}
var appContext:App.Context;

// ... app context retrieval

function authenticate( username, password, rememberMe ) {
    return appContext.authenticate( username, password ).then(
        function( token ) {
            if( rememberMe ) {
                var cookieValue = JSON.stringify( {
                    expirationTime: token.expirationTime,
                    key: token.key
                } );
                setCookie( "auth-token", cookieValue, 3 );
            }
        }
    );
}

// When starting the application this method could be called to try to authenticate the agent and if not present him with a login form
function reAuthenticate() {
    var authCookie = getCookie( "auth-token" );
    if( authCookie === null ) return Promise.reject( "There's no saved token to authenticate with" );

    var savedToken;
    try {
        savedToken = JSON.parse( authCookie );
    } catch( error ) {
        deleteCookie( "auth-token" );
        return Promise.reject( "The saved token couldn't be parsed" );
    }

    return appContext.authenticateUsing( "TOKEN", savedToken ).catch(
        function( error ) {
            if( error instanceof Errors.IllegalArgumentError || error instanceof HTTP.Errors.UnauthorizedError ) {
                // Invalid token
                deleteCookie( "auth-token" );
                return Promise.reject( "The saved token was invalid" );
            } else return Promise.reject( error );
        }
    );
}

// Simple function to retrieve a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function getCookie( name ) {
    var cookies[] = document.cookie.split( ";" );
    for( var i = 0, length = cookies.length; i < length; i++ ) {
        var cookie = cookies[ i ].trim();
        if( cookie.indexOf( name + "=" ) === 0 ) return c.substring( ( name + "=" ).length, cookie.length );
    }
    return null;
}
// Simple function to set a cookie using vanilla JavaScript. jQuery $.cookie method could be used instead
function setCookie( name, value, days ) {
    var expires = "";
    if( days ) {
        var date = new Date();
        date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
}
// Simple function to delete a cookie using vanilla JavaScript. jQuery $.removeCookie method could be used instead
function deleteCookie( name ) {
    setCookie( name, "", -1 );
}

Logging out

Clearing the authentication of an agent can be done by using the clearAuthentication method of the Auth service. E.g.:

let appContext;

// ... app context retrieval

appContext.auth.authenticate( "agent@example.com", "SomeOtherPassword" ).then(
    ( token ) => {
        console.log( appContext.auth.authenticatedAgent ); // Agent

        appContext.auth.clearAuthentication();

        console.log( appContext.auth.authenticatedAgent ); // null
    }
);
import * as App from "carbonldp/App";
import * as Token from "carbonldp/Auth/Token";

let appContext:App.Context;

// ... app context retrieval

appContext.auth.authenticate( "agent@example.com", "SomeOtherPassword" ).then(
    ( token:Token.Class ) => {
        console.log( appContext.auth.authenticatedAgent ); // Agent

        appContext.auth.clearAuthentication();

        console.log( appContext.auth.authenticatedAgent ); // null
    }
);
var appContext;

// ... app context retrieval

appContext.auth.authenticate( "agent@example.com", "SomeOtherPassword" ).then(
    function( token ) {
        console.log( appContext.auth.authenticatedAgent ); // Agent

        appContext.auth.clearAuthentication();

        console.log( appContext.auth.authenticatedAgent ); // null
    }
);