Good afternoon,

We are developing a PoC with OutSystems, and we stumbled on a problem we can't seem to solve.

Our application needs to let the user log-in using an external API (where the whole user management is) and not OutSystems' authentication mechanism. We know the downsides of this choice, but there are stronger reasons that make us go forward with it.

We tried to use the OS best practices, by splitting the app into layers. However we failed as a first step, so we went forward in a single web application layer. What happens here is that the user logs in into an external API, gets back a token, the token is stored in the session and in the OnBeforeRequest it is attached to each REST call.

This means that the token is not an API key. It is retrieved by letting the user log in into the external API, and all requests should have this token, because the API needs to know which user is doing what.

As far as the Web application is concerned, this works fine. OnBeforeRequest accesses the session, checks if a valid token is available, if yes it puts the token into an header, if not it redirects to the login page.

Now we want to refactor this into layers, because the next step is a Mobile app and most of the business logic has to be reused. However, we can't find a way to refactor it. The session is not available in the service layer, the only way to attach an header to a REST call is by using the OnBeforeRequest, and OnBeforeRequest does not accept input parameters!

Even if we perform a login request before each REST call, this still doesn't work. Where do we store username and password? (and it's a bad choice anyway).


Did any of you stumble on this issue? Did you manage to solve it?

Thanks for your help,

Massimo

Hello Massimo,

First, I'll ask why aren't you executing the login IN OutSystems AFTER login in the External Authentication? This would still let the authentication be managed by the external API, but you would have all the facilities of being logged in OutSystems.

Second, Session variables aren't sharable between modules directly, but you can share them indirectly. In the module where the Session Variable is defined, create a pair of wrapper public actions (Set/Get). They have access to the session variable because they are in the same module, and you can use them to set or get the value from different modules. Where you would use the session variable outside the module, use the Set or Get accordingly.

I think this would solve the problem of split the logic into different modules/layers.

Hope this helps.

Cheers.

I think what you should be storing on the database is your authorisation context, not the username / password as you mentioned.

Quick question: are you mapping this external login with an OutSystems user? I think you should, and in this case you should create an extension to your OutSystem user where you could store this authorisation token. And then, in your underlying layers, you should call the GetUserId() function to get the currently authenticated user id, and then retrieve the associated authorisation context.

Never done this in OutSystems, but it seems the correct way to do it.

Eduardo Jauch wrote:

Hello Massimo,

First, I'll ask why aren't you executing the login IN OutSystems AFTER login in the External Authentication? This would still let the authentication be managed by the external API, but you would have all the facilities of being logged in OutSystems.

Second, Session variables aren't sharable between modules directly, but you can share them indirectly. In the module where the Session Variable is defined, create a pair of wrapper public actions (Set/Get). They have access to the session variable because they are in the same module, and you can use them to set or get the value from different modules. Where you would use the session variable outside the module, use the Set or Get accordingly.

I think this would solve the problem of split the logic into different modules/layers.

Hope this helps.

Cheers.

Thank you for your kind answer! I would like to avoid authenticating twice, it would require the users to be copied over, quite not a good thing I would say.

I am very interested in the wrapper strategy you suggested. Could you please elaborate on that? Having a get/set pair would mean calling this methods from the service layer (in OnBeforeRequest), but a lower layer can't call an upper layer. How to do so?

Thanks!


Hello Massimo,

There is no need to authenticate twice when you use External Authentication.

The System module has an action called Login that receives a User Identifier and log in this user without the need of the credentials.

So, if the External Authentication return that the user was authenticated, you simply "Login" the user in OutSystems . You just create the user if the user does not exist, and all of this can be done automatically.

You can check this lesson to take a look: https://www.outsystems.com/learn/lesson/1306/external-authentication-providers/?LearningPathId=0 

Regarding the Session Variable, I would place it in a module in the Library layer (even its own module, for example), and this way I would avoid violating the No Upward Reference. It would be basically only a "storge", without logic associated directly to it.

Doesn't know if there is a better way (other than work directly with the database, instead of the Session Variable).

Cheers.

Eduardo Jauch wrote:

Hello Massimo,

There is no need to authenticate twice when you use External Authentication.

The System module has an action called Login that receives a User Identifier and log in this user without the need of the credentials.

So, if the External Authentication return that the user was authenticated, you simply "Login" the user in OutSystems . You just create the user if the user does not exist, and all of this can be done automatically.

You can check this lesson to take a look: https://www.outsystems.com/learn/lesson/1306/external-authentication-providers/?LearningPathId=0 

Regarding the Session Variable, I would place it in a module in the Library layer (even its own module, for example), and this way I would avoid violating the No Upward Reference. It would be basically only a "storge", without logic associated directly to it.

Doesn't know if there is a better way (other than work directly with the database, instead of the Session Variable).

Cheers.

I would complement the first part of this answer (that's what I meant with "mapping the external login with an OutSystems user" anyway) with my suggestion.

So instead of storing the token on the session (that can expire way before your actual token, thus having to login to your external IdP unnecessary times - in fact every time per session), I would create an authorisation context in your database associated with each OutSystems user. This is no more than a table with a FK to the Users table, a column to store your token, and probably an expiry time.

Hi Rui, 

Yes. I understood your answer. I was just trying to be more explicity on our answers. 

Regarding the database approach, it depends on what is the user session timeout, and how the external authentication system handles this aspect. If the externalnsystem is more 'severe', with a short session period, the session variable approach is usually simpler than have to implement the logic to handle the tokens per user/session. It's important to remember that if the user let the session timesout, usually it will require a new login anyway, and as this is handled by an external api, you will have to reach it again and it will return the token again, making the database storage an unnecessary step. 

But depending on the context I agree that a database approach may be better. 

Cheers