After reading James Wards artice on Securing Single Page Apps and REST Services, I'd very much like to implement this in Dart. However I have found so few examples in Dart on the topic of authentication. I'm particularly interested implementing steps 6 - 9 from the article:
The server validates the login information and creates an
authentication token for the user
The server sets the authentication
token in a cookie and returns it to the JavaScript application
The JavaScript application makes a request for some protected data,
sending the authentication token in a custom header
The server validates the token and then returns the data
Can someone provide a simple client/server example of this in Dart. Thanks in advance.
I would suggest the easiest thing to do is to use the Google OAuth2 pub package with Dart on the server to generate a token as described in this tutorial.
If you want to use cookies to store the token as James suggests, you can do so like this:
document.cookie = "token=TOKEN;max-age=${60*60*24*7*4}";
You read the cookie like this:
var token = document.cookie.replace(/(?:(?:^|.*;\s*)token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
And send it back in a custom header like this:
HttpRequest req = new HttpRequest();
req.open("Get", "www.server.com");
req.setRequestHeader("custom-token-header", token);
Then you can validate the token as described in the tutorial.
Related
I’m in process of developing system which consists from such parts:
- Some services under gateway (Ocelot)
- Mobile client (iOS)
- Identity Server 4
Mobile client hasn’t been prepared yet, so I use Postman for emulating requests from it. My problem is implementation of Authentication with External providers, like Google. It’s my first experience of using IS 4, so I have some misunderstanding and difficulties. Excuse me, if my question is too abstract or if I miss smth obvious.
I successfully deployed IS 4 using all this tutorials and it works with Password Credentials flow in a proper way: I request IS for access token, sending user credentials, it returns token and I can successfully use it for access to my API methods.
Situation with External Providers are different. I’ve overviewed this tutorial (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-3.1) and some other and add code from it to the IS project. I can successfully log in with Google, using a button on that IS4 web-page which goes with IS 4 Quickstart UI template. But no chance to work with API. As I understand in such workflow client-app should go for a token not to my IS as in example with a local user, but to the Google Auth provider. And I emulated it with Postman and got a strange access_token which has no data and it_token which contains username, email and so on. I try to use this id_token with requests to my API. The result is always 401.
Where I’m wrong? How should I build requests to API with token from Google? Or I have misunderstanding and there should be another flow: client goes to IS with specific request, IS goes to Google and then returns proper token to Client?
Here is configuration of authecation on the side of Web API app:
private void ConfigAuthentication(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "k_smart_api";
});
}
Here is config of Google-Auth on the side of IdentityServer:
services.AddAuthentication().AddGoogle(opts => {
opts.ClientId = "My google client Id";
opts.ClientSecret = "my google client secret";
opts.SignInScheme = IdentityConstants.ExternalScheme;
opts.SaveTokens = true;
});
This is how I get Access Token:
postman exampple
The tokens you get back from Google, is only used to Authenticate the user in Identity Server. Then after Identity Server receives those tokens, it sign-in the user and create new tokens (ID+access) that are passed to your client. you should look at using the authorization code flow in your client to authenticate the user and to get the tokens. then use the access token received to access your API.
do remember that the tokens received from Google are not used to give access to your APIs.
I have a mobile app which will call a REST API written using Laravel(5.2) framework.
This article on Laravel API authentication mentions how to authenticate users making calls to such an API. The caller should send the correct api_token to the server in the request.
My question is what would be a good way to get the api token to the mobile app? I'm currently thinking of creating a rest api which will authenticate the user based on username and password sent in the request and send the api_token in the response if the user sends a valid username/password pair. Is this method correct/secure? What things should I consider additionally if I do use this method?
You must use one of this methods to have a secure API
JWT TOKEN https://github.com/tymondesigns/jwt-auth
OAUTH2 https://github.com/lucadegasperi/oauth2-server-laravel
With this methods you only send once username and password and you obtain a token that is valid for a time you can decide. But as bigger is the time, more insecure.
To solve this, there are a renew token methods. With a valid token, you can obtain another valid and refresh the old. In this way, the username and password are more protected because they are not sent in every request.
Is not a good idea have the same token for each user all the time, as you saw in the example you provide. It´s very insecure. If someone get this token, he always will can send request in your name. The tokens must have a lifetime.
to answer your question how to send API token to mobile app i will recommend you that your mobile apps get a valid token and after refresh it.
Something as this works great to get a token in your app:
if ( thereAreTokenStored() )
{
if (! theTokenStoredIsValid() )
{
$authentication = refreshToken();
}
}
else
{
$authentication = authenticate();
}
To know all this issues I recommend you this book: https://apisyouwonthate.com/ . I learnt a lot of the 'API WORLD' with this book. It will help you to know all you need to create an API in a professional way and will provide the necessary tools and packages to achieve it and save a lot of work. And you will love your API!!
Yes this approach is safe. Additionally you also need to secure your connection to server by using HTTPS with a SSL certificate.
I am trying to create a Web API that allows the API's clients (native mobile apps) to login using a 3rd party cloud storage provider. I'm using the following general flow from Microsoft:
Here is what I am trying to achieve:
I am using the default ASP.NET Web API Visual Studio template with external authentication, along with the OWin.Security.Providers Nuget package for Dropbox login functionality, and the existing built-in login functionality for Google (Drive) and Microsoft (OneDrive).
The issue I'm having is that the built-in functionality all seems to do the authentication and authorization as part of one flow. For example, if I set up the following in Startup.Auth.cs:
DropboxAuthenticationOptions dropboxAuthOptions = new DropboxAuthenticationOptions
{
AppKey = _dropboxAppKey,
AppSecret = _dropboxAppSecret
};
app.UseDropboxAuthentication(dropboxAuthOptions);
... and navigate to this url from my web browser:
http://<api_base_url>/api/Account/ExternalLogin?provider=Dropbox&response_type=token&client_id=self&redirect_uri=<api_base_url>
I am successfully redirected to Dropbox to login:
https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id=<id>&redirect_uri=<redirect_uri>
... and then after I grant access, am redirected back to:
http://<api_base_url>/Help#access_token=<access_token>&token_type=bearer&expires_in=1209600
... as you can see the token is part of that, so could be extracted. The problem is that the client needs to be the one navigating to Dropbox and returning the authorization code back up to the Web API, and the Web API would send the authorization code back to the third party to get the token which would then be returned to the client... as shown in the diagram above. I need the ExternalLogin action in the AccountController to somehow retrieve the Dropbox url and return that to the client (it would just be a json response), but I don't see a way to retrieve that (it just returns a ChallengeResult, and the actual Dropbox url is buried somewhere). Also, I think I need a way to separately request the token from the third party based on the authorization code.
This post seems a little similar to what I am trying to do:
Registering Web API 2 external logins from multiple API clients with OWIN Identity
... but the solution there seems to require the client to be an MVC application, which is not necessarily the case for me. I want to keep this as simple as possible on the client side, follow the flow from my diagram above, but also not reinvent the wheel (reuse as much as possible of what already exists in the OWIN/OAuth2 implementation). Ideally I don't want the client to have to reference any of the OWIN/OAuth libraries since all I really need the client to do is access an external url provided by the API (Dropbox in my example), have the user input their credentials and give permission, and send the resulting authorization code back up to the api.
Conceptually this doesn't sound that hard but I have no idea how to implement it and still use as much of the existing OAuth code as possible. Please help!
To be clear, the sample I mentioned in the link you posted CAN be used with any OAuth2 client, using any supported flow (implicit, code or custom). When communicating with your own authorization server, you can of course use the implicit flow if you want to use JS or mobile apps: you just have to build an authorization request using response_type=token and extract the access token from the URI fragment on the JS side.
http://localhost:55985/connect/authorize?client_id=myClient&redirect_uri=http%3a%2f%2flocalhost%3a56854%2f&response_type=token
For reference, here's the sample: https://github.com/aspnet-security/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Mvc/Mvc.Server
In case you'd prefer a simpler approach (that would involve no custom OAuth2 authorization server), here's another option using the OAuth2 bearer authentication middleware and implementing a custom IAuthenticationTokenProvider to manually validate the opaque token issued by Dropbox. Unlike the mentioned sample (that acts like an authorization proxy server between Dropbox and the MVC client app), the JS app is directly registered with Dropbox.
You'll have to make a request against the Dropbox profile endpoint (https://api.dropbox.com/1/account/info) with the received token to validate it and build an adequate ClaimsIdentity instance for each request received by your API. Here's a sample (but please don't use it as-is, it hasn't been tested):
public sealed class DropboxAccessTokenProvider : AuthenticationTokenProvider {
public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context) {
using (var client = new HttpClient()) {
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.dropbox.com/1/account/info");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.Token);
var response = await client.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK) {
return;
}
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var identity = new ClaimsIdentity("Dropbox");
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, payload.Value<string>("uid")));
context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
}
}
}
You can easily plug it via the AccessTokenProvider property:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions {
AccessTokenProvider = new DropboxAccessTokenProvider()
});
It has its own downsides: it requires caching to avoid flooding the Dropbox endpoint and is not the right way to go if you want to accept tokens issued by different providers (e.g Dropbox, Microsoft, Google, Facebook).
Not to mention that if offers a very low security level: since you can't verify the audience of the access token (i.e the party the token was issued to), you can't ensure that the access token was issued to a client application you fully trust, which allows any third party developer to use his own Dropbox tokens with your API without having to request user's consent.
This is - obviously - a major security concern and that's why you SHOULD prefer the approach used in the linked sample. You can read more about confused deputy attacks on this thread: https://stackoverflow.com/a/17439317/542757.
Good luck, and don't hesitate if you still need help.
I am using Yesod to build a purely REST backend for an Angular based application. This application will be hosted separately with a CDN and will need to connect to the Yesod api as well as a few others. Is there a way to have Yesod accept a Bearer token instead of using a cookie session for authentication?
We do something similar in www.fpcomplete.com. You can do this by overriding the maybeAuthId method in the YesodAuth typeclass to check for the Bearer token. For fpcomplete.com, we check for an authorization request header, which looks something like:
req <- waiRequest
mUserId <-
case lookup "authorization" (requestHeaders req) of
Nothing -> doNormalAuthentication
Just authHeader -> checkAuthHeader
I have this scenario: a corporate site (MVC 4) and a web shop; add OAuth 2 SSO functionality. Both sites have their own members, but the corp site (for which I'm responsible) must also work as an OAuth 2 authorization server and will store a web shop user id for each member. The shop requested the following endpoints:
Auth endpoint
• authorization:
…/oauth2/authorize?client_id={CLIENT_ID}&state={STATE}&response_type=code&redirect_uri={REDIRECT_URI}
• token
…/oauth2/token?code={TOKEN}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri={REDIRECT_URI}&grant_type=authorization_code
…/oauth2/token?refresh_token={TOKEN}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri={REDIRECT_URI}&grant_type=refresh_token
API endpoint
• getid (will return JSON with the shop id of the member):
…/oauth2/api/getid?access_token={TOKEN}
I don't have experience with OAuth, so I was looking at the DotNetOpenAuth samples and have concluded that I need to implement an OAuthAuthorizationServer, but modifying the sample to fit my requirements is difficult as it seems to do more and is complex.
As researching DotNetOpenAuth seems to be so time consuming, I'd like to ask: is modifying the OAuthAuthorizationServer sample the right approach? Or should I try to make a native implementation or try a different OAuth library that may be easier to use in my situation?
Please comment on my overall plan:
-keep the corp site member login flow standard forms auth, straightforward LogOn controller
-add an OAuth controller that will implement the three required endpoints as actions
-when the authorization action is reached, I validate the client and redirect to LogOn passing on the redirect_uri; I think the Authorize ActionResult from OAuthController.cs from the sample is where I should start investigating this, and return an AccountAuthorizeModel. Is this correct?
-after the user logs in, and if the login page was reached from the authorization endpoint, I redirect to redirect_uri with the code attached; I don't know where to start with this one. PrepareApproveAuthorizationRequest then PrepareResponse? Where does the code come from? Where in the flow should I add a new ClientAuthorization in the database?
-the shop will then use the code to get or refresh the token, from the /token endpoint; simply return HandleTokenRequest?
-with the token the shop site will be able to get the member data JSON; have to find out how to validate the token
Now, besides adding a Clients table to store the client ids and secrets, and ClientAuthorization to keep track of who's authorized, I don't know if the other tables from the DotNetOpenAuth sample are used and when: Nonce, SymmetricCryptoKey, User.
Modifying OAuth2AuthorizationServer.cs seems straightforward, I only have to add real certificates and make sure the clients are pulled from my data context.
Thanks!
I think you are right in most of the points. Let's comment them:
OAuth server should have 2 endpoints (not 3), as requesting token and refreshing token goes to the same endpoint (TokenEndpoint).
It depends if your are going to implement a different authentication server (or controller), or you are going to implement the authentication responsibility inside the authorization server. In case they are separated, the authentication server should be the one responsible of displaying the logon, authenticate and communicate with authorization server using OpenID protocol (Also supported by DotNetOpenAuth).
Once the user is authenticated, the authorization server should store the data of the user identity somehow, and return the authorization code (if using this Oauth flow) using DotNetOpenAuth functions:
var response =
this.AuthServer.PrepareApproveAuthorizationRequest(AuthorizationRequest,
User.Identity.Name);
return this.AuthServer.Channel.PrepareResponse(response);
finalResponse.AsActionResult();
I don't think you need to save nothing about the authorization process in the database, and the code is generated by DotNetOpenAuth and sent to the client into the query string of the redirection.
Then, the client should get the code (ProcessUserAuthorization) and call the TokenEndpoint. This endpoint is just returning HandleTokenRequest, that internally is calling to some OAuthAuthorizationServer functions, such as CreateAccessToken.
Once the client has the access token, it should call the resources, sending the token into the HTTP Header 'Authorization'. The resource server is the responsible to validate the token.
var resourceServer = new ResourceServer(new
StandardAccessTokenAnalyzer(signing, encrypting));
AccessToken token = resourceServer.GetAccessToken(request, scopes);
A store provider for nonce and crytoKeys is needed using this flow. Have a look to class InMemoryCryptoKeyStore in:
https://github.com/DotNetOpenAuth/DotNetOpenAuth/wiki/Security-scenarios
Hope this helps!