Description
There are some issues and pull requests that try to fix this by implementing other storage managers, based on Web Storage API. I think we should think about a different approach, which would be simpler to maintain, and would lead to a more user-friendly API. It would be a major breaking change, but would simplify the API by removing the dependency on $cookies
service. My suggestion takes some clues from reflective meta programming, and it is quite simple. I consists on redefining the semantics of the storage operations by passing a target object, such as $cookies
it would be possible to map its methods to an abstract storage service. Example:
Configuration remains the same.
// oauth-token-config.js
myModule.config(OAuthTokenProvider => {
OAuthTokenProvider.configure({
name: 'token',
options: { secure: true }
});
});
Using $cookies
. This should be done in a run block to allow injecting third party dependencies.
// oauth-token-run.js
myModule.run(($cookies, OAuthToken) => {
// Cookies example.
OAuthToken.extend($cookies, config => {
return {
getToken: {
method: 'getObject',
args: [config.name]
},
removeToken: {
method: 'removeToken',
args: [config.name, config.options]
},
setToken: data => ({
method: 'putObject',
args: [config.name, data, config.options]
})
}
}));
Using sessionStorage
:
// oauth-token-run.js
myModule.run(() => {
// sessionStorage example.
OAuthToken.extend(sessionStorage, config => {
return {
getToken: {
method: 'getItem',
args: [config.name]
},
removeToken: {
method: 'removeItem',
args: [config.name]
},
setToken: data => ({
method: 'setItem',
args: [config.name, JSON.stringify(data)]
}),
}
}));
The implementation of the OAuthToken
would be straight forward, such as:
class OAuthToken {
extend(target, handlers) {
this.storageService = target;
this.handlers = handlers(config);
}
setToken(data) {
// We should execute validations to check it the storage service was set.
const { args, method } = this.handlers.setToken(data);
this.storageService[method](...args);
}
getToken() {
const { args, method } = this.handlers.getToken;
this.storageService[method](...args);
}
removeToken() {
const { args, method } = this.handlers.removeToken;
this.storageService[method](...args);
}
}
As I've mentioned in the comment on setToken
we should validate on each method if both target
and the required method were defined. This might seem a lot more configuration, and should be well documented, but this solves the following recurrent issues:
- Removes dependencies from third-party storage libraries -
$cookies
. - Avoids maintaining a large code base prone to bugs, and not scalable, with naive implementations, that don't take basic security considerations.
- Adds flexibility to implementing other modules than Web Storage (both localStorage and sessionStorage) and cookies.
@ruipenso what do you thing? It would be awesome if someone this :)