OAuth Authentication and API Access Control
This module provides two different kinds of OAuth services:
- Access control for APIs using OAuth tokens
- Authentication with external identity providers (LinkedIn, Twitter, Facebook, etc.)
API access control
This is handled with a Bearer token in the Authorization HTTP header.
There is not yet an admin interface to make generate the tokens.
However, there is an Erlang API:
SudoContext = z_acl:sudo(Context),
% Make a new OAuth2 token with full access to the admin (user 1) account
TokenProps = #{
<<"is_read_only">> => false,
<<"is_full_access">> => true
},
% Insert the token rights into the database, couple it to user 1.
% The returned id is a simple serial number.
{ok, TokenId} = m_oauth2:insert(1, TokenProps, SudoContext),
% Generate a token, it is valid for 3600 seconds (pass 'undefined' if no expiration).
% This token is a signed and encrypted binary that can be used in the
% Authorization header.
{ok, Token} = m_oauth2:encode_bearer_token(TokenId, 3600, SudoContext),Use the token to make an API request:
Url = z_context:abs_url( z_dispatcher:url_for(api, [ {star, <<"model/acl/get/user">> } ], Context), Context),
{ok, {_, _, _, Body}} = z_url_fetch:fetch(Url, [ {authorization, <<"Bearer ", Token/binary>>} ]),
% The user-id associated should be '1', as was defined when inserting the token.
#{ <<"result">> := 1, <<"status">> := <<"ok">> } = jsxrecord:decode(Body),Authentication with identity providers
Uses OAuth2 to:
- Sign up users using an external (trusted) identity service
- Log in using the external service
- Associate an external service user with an existing user
Steps for the OAuth redirections to the external service
Click on button, this opens a new window
In the window load a page, load a page that will redirect to the correct service:
{% url logon_service service='twitter' is_connect=is_connect %}This URL and template are proviced by
mod_authentication. The page then includes a template that will perform the correct redirect, the name of the page is"_logon_service."++q.service++".tpl"This service template should be provided by the module implementing the given service.
The service template is loaded lazy, so that the correct
z.authcookie can be set for this page. This is needed as the server will store information in the server side session storage.Authentication at the external service
Redirect back to our server, using the url
oauth-service/redirectThis displays a new page, which (after reconnecting with the server) will send a message to the server. This message includes all query arguments passed to the URL.The server checks the passed query arguments and then:
a. If log in and all ok: server posts to auth-client-model to re-authenticate using a special one-time token. This sets a new z.auth cookie and forces all tabs to re-authenticate using the new user id. After the identity is changed the popup window is closed (using a data attribute on the body tag, handled by the ui model).
b. If connect and all ok: the identity is added to the current user-id, popup-window is closed.
c. If log in but needs confirmation: render a confirm template. The confirm button will send a message to the server to create the new user and then the server proceeds to step (a).
d. On an error: display an error message.
Any browser tab that was open will get a message via the ServiceWorker that the authentication has been changed. This fill will force a re-sync using the new z.auth cookie.
Problems:
- Race-condition setting the new z.auth cookie and refresh by other tabs of the same cookie. This is a generic problem, that should be solved in the auth client model.