I've just started implementing Authentication in my Web API.
I want to start with Basic Authentication
I learned that i've to pass Username and Password in every request.
So, lets say i'm doing some Admin task and making API call for same like this:
$.ajax({
url: host + "homework/delete/" + $(this).data("id"),
type: 'DELETE',
headers:
{
Authorization: 'Basic ' + btoa(username + ':' + password)
},
success: function (d) {
$tr.remove();
},
error: function () {
alert("Error please try again");
}
});
So, although my username/password is in variable, but their value must be at page(source). whosoever access that page, can see those credentials.
That means, whosoever get to know the url of that page, can see the credentials.
If i put a login page, how should i check on admin page that this user is authenticated. Should i use Cookies? to set something if user is coming through login page?
To enhance security, I think there should be another approach. At first you need to authenticate to you service using username and password, and receive authentication token with limited lifetime, then you should use this token to access your services.
I think you have to choose another approach:
create a server side application with UI (PHP, Java, ...)
this application has a session management
the credentials are stored in the configuration of the server side app
the requests to the service which is secured by Basic Authentication are performed by the server app. The responses are delivered to the client
You can't hide the credentials if you are creating a client side JavaScript application. Another issue with your approach maybe this: does the secured service support CORS (cross origin resource sharing) ?
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'm unable to authenticate / sign-in via AzureAD when running testCafe.
const testrole = Role(
'https://login.microsoftonline.com/',
async t => {
await t
.typeText(Selector('input').withAttribute('type', 'email'), *******)
.click(Selector('#idSIButton9'))
.typeText(Selector('input').withAttribute('type', 'password'), ********)
.click(Selector('#idSIButton9'));
},
{ preserveUrl: true }
);
The above steps work fine, however after entering the password I get a message saying:
"Unable to sign in to Outlook account, Error: AADSTS900561: The endpoint only accepts POST requests. Received a GET request."
From my initial search, it seems like something to do with 3rd party cookies on the browser. However, I'm unable to find a solution at this time.
Any idea how I get around this issue?
The Azure AD product team has always reminded me that it is a bad idea to try to automate sign in like that.
They will probably detect that you are a bot and start blocking your requests, even if you succeed.
Instead, to acquire access tokens you need to use either the client credentials flow (for app-only tokens) or the resource owner password credentials flow (for delegated user tokens).
Client credentials flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
ROPC flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
You have to take good care to secure the credentials used for testing.
And use a test tenant if possible.
We have a web application and enabled direct client channel to communicate with the hosted BOT framework using directline secret.
Link :BOT - Directline webchat
Sample Code:
BotChat.App({
directLine: { secret: Key },
//dynamically retrieve the logged in user info in your mvc View once the user logged in and pass it on
//and pass thoes info to your bot
user: { id: '', email: '' },
bot: { id: 'testBOT' },
resize: 'detect'
}, document.getElementById("divbot"))
Here is my situration:
1) The user successfully logged in to the application and authorized using the individual account
2) How to authenticate the user in the BOT framework. The Directline secret used to authenticate the calling application. Is there any way to authrorize the authenticate the logged in user in the BOT framework securely?
Thank you
also read about getting the secret token from the key and use for communication. But not sure how to accomplish in the javascript.
It seems that you embed web chat in your MVC website, and you do not want to expose Direct Line Secret (which prevent anyone from putting your bot on their website). You can try this approach:
Create a backend service, and make request to generate Direct Line token in that service, which can avoid exposing Direct Line Secret from client side.
On your JavaScript client, you can make Ajax request to that backend service for getting Direct Line token and initiate BotChat with generated token in Ajax success callback function.
Enable CORS in your backend service to allow some origins and prevent another origins request from accessing that backend service and adding your bot in web page.
For secure your backend service, you can implement request Authentication for it.
You can exchange the key for a token that expires. Here is an mvc example: https://github.com/EricDahlvang/TokenBotExample/tree/master/TokenBotExample
string botChatSecret = ConfigurationManager.AppSettings["BotChatSecret"];
var request = new HttpRequestMessage(HttpMethod.Get, "https://webchat.botframework.com/api/tokens");
request.Headers.Add("Authorization", "BOTCONNECTOR " + botChatSecret);
using (HttpResponseMessage response = await new HttpClient().SendAsync(request))
{
string token = await response.Content.ReadAsStringAsync();
Token = token.Replace("\"", "");
}
I am having a HTML (Angular) site which has a login button and needs (of course) to present a different GUI when the user is authenticated. I am using ServiceStack based REST services. Now when a user is successfully authenticated I was wondering if it is possible to check the generated authentication cookie (by ServiceStack) on the client only. I just need to check the userid, maybe role and expiration date of the cookie. Advantage is I do not have to make 'CheckUserIsAuthenticated' server rest call's just for showing a different GUI (of source CRUD actions are validated serverside).
You can check that a cookie exists with document.cookie, as it's hard to work with directly Mozilla provides a lightweight cookies wrapper to make it easier to work with, likewise AngularJS provides $cookies provider.
But a cookie doesn't tell you anything about the user since even non-authenticated / anonymous users will have cookies. Instead to check if the user is authenticated you can call /auth route via ajax which when authenticated ServiceStack will return summary info about the user, e.g:
{
UserId: "1",
SessionId: "{sessionId}",
UserName: "user#gmail.com",
DisplayName: "First Last"
}
If the user is not authenticated /auth will return 401 Unauthorized.
I have an application that uses google's oauth system to authorize with youtube's api. The code for this is done on our server and we receive tokens without any problem. We'd like to move some of the api calls to the client using their javascript api.
Since we've already authorized the user with the correct scopes required for the youtube api (https://www.googleapis.com/auth/youtube) I assumed when I called authorize on the client it would know that my application was already authorized and allow auto login. Instead I receive a "immediate_failed" response. Does anyone know why? Thanks!
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
If you have the token, you can just use setToken instead of going through OAuth2 again.