How to make ACL logic use OAuthToken model? - access-token

When loopback-component-oauth2 is used for implementation of oauth2 server, it makes special model to manage oauth2 token, named by OAuthToken.
Once user is authenticated whatever authorization type is, a token is saved as instance of OAuthToken Model
But loopback's ACL uses 'AccessToken' model, which is inbuilt model of loopback module.
So in this case, loopback's ACL doesn't work well because it searches request token from AccessToken, not OAuthToken.
Is there any way to change token model for ACL? How to make ACL search access token in OAuthToken model?
Thank in advance.

It's a TODO on our roadmap. See https://github.com/strongloop/loopback/issues/817.
BTW, the oAuth 2 authentication middleware will set the instance of OAuthToken into req.accessToken. Do you see any ACL code that checks the type of req.accessToken?

Related

AWS Cognito: Add custom claim/attribute to JWT access token

My app creates a custom attribute "userType" for each new signed-up user. Now I would like this "userType" claim/attribute to be added to the JWT access token whenever the user signs in or the token gets refreshed.
Is there an option to tell cognito to add my custom claim/attribute to the JWT access token? (Without a pre token generation Lambda)
Custom attributes are not available in Cognito access token. Currently it is not possible to inject additional claims in Access Token using Pre Token Generation Lambda Trigger as well. PreToken Generation Lambda Trigger allows you to customize identity token(Id Token) claims only.
You can use ID token to get the token with custom attributes.
Access tokens are not intended to carry information about the user. They simply allow access to certain defined server resources.
You can pass an ID Token around different components of your client, and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them.
How to retrieve Id token using amazon cognito identity js
cognitoUser.authenticateUser(authenticationDetails,{
onSuccess: function(result) {
var accessToken = result.getIdToken().getJwtToken();
console.log('accessToken is: ' + accessToken);
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
},
});
I have the same problem when I want to create several microservice. There isn't a way I can customize an access token, but only an identity token. However, I use client credentials in the machine-to-machine which needs access token. So, in no way I can customize my token. At last, I decide to add such info(like user type) in the event header. It's not a very secure way compared to customize a token, but there isn't any other easy way to do it right now. Otherwise, I have to rewrite the authorizer in Cognito. Like rewriting a customize authorizer and it's very painful.
I have the same issue with Cognito; exist other tools like "PingFederate"Auth-server of Ping identity and Auth0 Auth-server; I know that the requirement isn't part of the standard, but these applications were my alternatives to fix this issue
The responses suggesting to use the ID Token for authorization in your backend systems are bad security practice. ID Tokens are for determining that the user is in fact logged in and the identity of that user. This is something that should be performed in your frontend. Access Tokens on the other hand are for determining that a request (to your backend) is authorized. ID Tokens do not have the same security controls against spoofing that Access Tokens have (see this blog from Auth0: https://auth0.com/blog/id-token-access-token-what-is-the-difference/).
Instead, I recommend that your backend accept an Access Token as a Bearer token via the Authorization HTTP header. Your backend then calls the corresponding /userinfo endpoint (see: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) on the authorization server that issued the Access Token, passing such said Access Token to that endpoint. This endpoint will return all of the ID Token information and claims, which you can then use to make authorization decisions in your code.

What to return after login via API?

I'm creating an API server which will be consumed by a mobile app that I will work on later. I have yet to see any reference of API best practices related to user flow and returned data even after searching for several hours.
My question is whether the login response of an API should return the a personal access token with the refresh token along with the user info? Or should I just return the token and make another API call for getting the user info.
I could just do what I have in mind but I'm trying to learn the best practices so that I don't have to adjust a lot of things later.
I need suggestions as well as good references related to my question.
Thank you.
It depends on what you are using for your authentication. If you are using libraries like Laravel Passport or JWT, you can have the token endpoint which returns the access token, refresh token, validity period and the token type (Bearer). You can then have an authenticated endpoint which will be used to get a user's profile based of the token passed in the request header.
However, if you go through the documentation for those libraries, in most there is an allowance to manually generate a token. You can use this in a custom endpoint that will return the token as well as the user profile Passport Manually Generate Token.
If you are using JWT, you can also embed a few user properties in the token itself. The client can the get the profile info from the JWT itself without having to make a round trip to the server. Passport ADD Profile to JWT
If you have a custom way in which you are handling authentication, you can pass the token as well as the user profile in the same response.
In the end, it's up to you to decide what suits you best.
Have you looked at OpenID Connect? It's another layer on top of OAuth 2.0 and provides user authentication (OAuth 2.0 does not cover authentication, it just assumes it happens) and ways to find information about the current user.
It has the concept of an ID_token, in addition to the OAuth access token, and also provides a /userinfo endpoint to retrieve information about the user.
You could put user information in your access token, but security best practice is to NOT allow your access token to be accessible from JavaScript (i.e. use HTTP_ONLY cookies to store your access token).

How to enrich/extend Auth class/data in Laravel 5?

In Laravel it's very useful to access Auth Facade after authentication in order to get user data like:
Auth::user()
What If during session and users interaction I'd like to enrich the object returned by the above call? Maybe assign some attributes to a user after he performed some action on my webapp?
E.g. A user performs a fast registration, and after while completes some other profile data. I'd like them to be available directly in Auth::user() instead of perform subsequent DB queries...
IMPORTANT
I'm integrating Auth0 into Laravel authentication. So the default driver/provider behind Auth is not Eloquent but Auth0.
Auth0 gives back a Json object containing all authenticated data.
Auth0User->userInfo
What I'm trying to achieve is to edit the Auth data after Auth0 Authentication by adding custom data to Session Object.
Basically I want to use another service to manage account related data, and use Auth0 only for managing user/password grant.
You can add a custom attribute to the User model. For example:
public function getTestAttribute()
{
return session()->get('test', 'defaultValue');
}
It is possible to set the session key somewhere else in your application:
session()->put('test', 'otherValue');

User registration for API/SPA

I am creating an API and a separate front-end app that will consume said API. In my particular case I'm using Laravel Passport for my API and some VueJS for my frontend app.
In order for a user to create an account, a user must POST to a route (/oauth/token) on the API which, requires a client_secret to be passed (https://laravel.com/docs/5.3/passport#password-grant-tokens).
The only options I see are:
Having the client_secret sent as a header from my frontend app. However, putting this token out in the open doesn't seem smart.
Don't require the client_secret at all. This doesn't seem much better than option 1.
Have a dynamic page on my frontend app that can securely store the client_secret and then send it to the API. While this is obviously the most secure, it seems to partially defeat the purpose of a fully static frontend (SPA).
What's the best practice for this type of approach? I've searched for how this is dealt with in general with an API and SPA, but I haven't found anything that points me in the right direction.
From my point of view, the Laravel Passport component seems to implement the OAuth2 Framework Protocol incorrectly.
The client_id and client_secret parameters are not part of the grant type.
For the Resource Owner Password Credentials grant type, the required parameters are username and password (see RFC6749 section 4.3.2).
client_id and client_secret are used to authenticate a confidential client that sends its credentials through the body parameters (see RFC6749 section 2.3.1). The Laravel Passport component should allow other client authentication schemes (especially the HTTP Basic Authentication Scheme). The RFC6749 also indicates that
Including the client credentials in the request-body using the two
parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
to directly utilize the HTTP Basic authentication scheme
The OpenID Connect Core specification lists some of those schemes in its section 9. The RFC6749 does not indicates how public clients (e.g. SPA) should authenticate against the token endpoint. They are supposed to use the Implicit grant type which does not require a client authentication.
Anyway, a solution could be to use a kind of proxy. This proxy has to be installed on a server. It will receive all requests from the SPA (without client secret), add the client secret and transmit the modified request to the Laravel Passport endpoint. Then the response is sent to the SPA. This way the SPA never exposes the client secret.
I came across the same problem, and I didn't find much more documentation on the problem.
So here is what I did, that seems working great so far, you'll tell me if you see anything wrong.
For my apps, I'll be using password grant clients that I create on the fly for each "client" of my app. By client I mean browser, or mobile app, or anything.
Each browser, checks at startup if they have any client_id and client_secret into localStorage (or cookies, or anything). Then, if they don't, they call an endpoint of your API that will create a password grant client and return the information to the browser.
The browser will then be able to login the user using this new client information and his credentials.
Here is the controller I use to create a password grant client:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Http\Request;
use Laravel\Passport\ClientRepository;
class AuthController extends Controller
{
protected $hasher;
protected $clients;
public function __construct (Hasher $hasher, ClientRepository $clients)
{
$this->hasher = $hasher;
$this->clients = $clients;
}
public function makeClient (Request $request)
{
$client = $this->clients->create(null,$request->header('User-Agent','Unknown Device'), '', false, true);
return $client->makeVisible('secret');
}
}
As you can see, as the name for the client, I try to store the User-Agent of the browser. So I can potentially display a page to my user with all his clients and giving him the right to revoke some clients like:
"Google Chrome, New York". You can also store the client IP or anything in there that will help you identify more precisely the client type of device...
The simpler way would be to take care of the user registration with the Laravel app running Passport itself (and not with the frontend Vuejs app via API).
Once the user is registered and logged in, you can use Passport's CreateFreshApiToken middleware to add a token to the user's cookie while loading up your frontend app. No more problem with client_secret.
See https://laravel.com/docs/5.3/passport#consuming-your-api-with-javascript and https://mattstauffer.co/blog/introducing-laravel-passport#super-powered-access-to-the-api-for-frontend-views
Also oauth/token doesn't create a user I believe? It is supposed to deliver a token (for password grant client) or an authorization code (authorization code grant client).

Programmatic authentication

I am using Spring Security in my application.
I have all the pages secured. But couple of URL needs to be available both for system user and anonymous user.
But anonymous user should not have direct access to the URLs. He gets a link with unique token and gets access to some URLS if this token is valid.
What I want to do is:
In controller check if token in URL is valid
If it is - authenticate user in the system programmatically using some predefined login and password. This user will be configured to have authority to access necessary URLs.
The question is:
Is this a correct approach to perform user authentication programatically with some roles in controller if token is valid? Is this safe approach?
Security is an aspect. An aspect can be decoupled from your main code (controller) to reduce code duplication and improve flexibility. Move authentication code from controller to new filter (be sure that this filter executed after spring security filter chain). You will be able secure new URLs via web.xml (zero lines of code).
I think the better way to do this is:
move the shared operations into service layer
define a controller for those anonymous user and make its authority
as anonymous
check the validity of token in this controller
if valid, call some services method to perform the operations.
render the result in this controller

Resources