I need to auth on the server that I'm trying to pull data from I currently have it connecting to the server with:
let urlString = "\(makeUrl(grammar: grammar))&\(query)"
let drop = Droplet()
return try drop.client.get(urlString)
But I can't seem to figure out how to get creds attached to the get request. I tried just putting the user and password into the url but found the vapor client doesn't allow that:
/*
Userinfo (i.e., username and password) are now disallowed in HTTP and
HTTPS URIs, because of security issues related to their transmission
on the wire. (Section 2.7.1)
*/
With a little nudge from the Vapor Slack channel and a little code diving in the AlamoFire repo I have found the solution.
First you need to base64 encode the username name and password and then add it to the http header.
func performRequest(query: String, grammar: FMPGrammar) throws -> Response {
let urlString = "\(makeUrl(grammar: grammar))?\(query)"
let loginString = "\(userName):\(password)"
let b64Login = Data(loginString.utf8).base64EncodedString(options: [])
let drop = Droplet()
let result = try drop.client.get(urlString, headers: [.authorization : "Basic \(b64Login)"])
return result
}
Like the error states, it is a HUGE security risk to include username/password credentials in plaintext as GET uri parameters. You should (at a minimum) be sending them in a POST call.
Check out the blog post on User Authentication with Vapor to see a pretty decent example of setting up user authentication with Vapor. The blog is a little old now (Vapor has changed a lot since then), but I think pretty much everything in it should still work. At least conceptually.
Also, you join the Vapor Slack channel and ask questions in there :)
qutheory.slack.com
Related
I have setup a new account and not verified my domain. I would like to test and confirm mail-send before proceeding with verification and adding payment information.
I have tried curl using the sandbox method and api key (including smtp). I have also tried to use my domain using the top account mail-address as recipient. But each time the send command (both curl and smtp) I get "Mailgun Magnificent API" response - but no mail is delivered. So far the Mailgun API does not look so Magnificent... I have gone through the documentation multiple times and cannot find what I might be doing wrong..
Any help is much appreciated.
Faced the same issue while sending emails via api by php curl. I solved it by changing API Base URL https://api.mailgun.net/v3/YOUR_DOMAIN_NAME to https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages.
It's because their api is not only for sending.
Hope this helps.
For anyone else trying to figure out what "Mailgun Magnificent API" means in a Mailgun HTTP 200-OK API response, it occurs when posting to https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/some/api/endpoint when /some/api/endpoint is not a valid Mailgun API endpoint.
If you are using a client library, there's probably a mistake in your Mailgun sender domain setting. Say you've verified the domain mg.example.com with Mailgun. Examples that can result in "Mailgun Magnificent API" (the exact setting name depends on the library):
MAILGUN_DOMAIN = mg.example.com # comment—this is a common mistake in dotenv files, which don't usually support inline comments; move the # comment to its own line
MAILGUN_DOMAIN = mg.example.com/mysite—get rid of the /mysite part
If you are posting directly to the Mailgun API (or developing a client library), there are some additional ways you might get "Mailgun Magnificent API":
Omitting the API endpoint: https://api.mailgun.net/v3/mg.example.com (as noted in another response)
Misspelling the endpoint: https://api.mailgun.net/v3/mg.example.com/massages (that should be messages with an e)
Including a # or ? after your domain: https://api.mailgun.net/v3/mg.example.com #/messages (see the note above about comments in config files)
Including an extra path after your domain: https://api.mailgun.net/v3/mg.example.com/route/to/my/app/messages
Note that you won't see "Mailgun Magnificent API" if YOUR_DOMAIN_NAME is not a valid sending domain you've registered with Mailgun. (In that case, Mailgun instead responds 404-Not Found).
The mailgun guide shows you to use https://api.mailgun.net/v3/YOUR_DOMAIN as YOUR_DOMAIN_NAME as in the snippet below and this was the problem.
If you're using mailgun-js, you simply need to have YOUR_DOMAIN as YOUR_DOMAIN_NAME.
No need for the https://api.mailgun.net/v3 part
const API_KEY = 'YOUR_API_KEY';
const DOMAIN = 'YOUR_DOMAIN_NAME';
const mailgun = require('mailgun-js')({apiKey: API_KEY, domain: DOMAIN});
const data = {
from: 'Excited User <me#samples.mailgun.org>',
to: 'foo#example.com, bar#example.com',
subject: 'Hello',
text: 'Testing some Mailgun awesomeness!'
};
mailgun.messages().send(data, (error, body) => {
console.log(body);
});
The problem for me was not including my domain name in the url and trying to type everything onto a single line. Strictly following their online example. Typing a backslash will bring your cursor to a new line.
$ curl -s --user 'api:key-xxx' \
https://api.mailgun.net/v3/your_domain/messages \
-F from='User <user#sample.mailgun.org>' \
-F to='xxx#gmail.com' \
-F subject='Hello' \
-F text='Testing some mailgun!'
Response
{
"id": "<xxx.x.xxx#your_domain>",
"message": "Queued. Thank you."
}
Including an slash "/" after messages url part at the end causes this failure too.
For example if you are using a library like Refit for c#, ensure your service interface be declared like this (see the Post attribute):
public interface IMailgunService
{
[Post("")]
Task<JsonDocument> SendEmailAsync([Body(BodySerializationMethod.UrlEncoded)] Dictionary<string, object> data);
}
You know, web applications needs sessions or cookies to authentication. I trying to build web application with Vue.JS and Flask microframework for example ERP or CRM.
I'm confused. How can I work with sessions? Let's think we have a code like this in the Flask:
import os
from flask import Flask, request, jsonify, abort, session
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY') or \
'e5ac358c-f0bf-11e5-9e39-d3b532c10a28'
#app.route('/login', methods=['POST'])
def user_login():
user = request.form['user']
session['isLogged'] = True
return jsonify({'status': session['isLogged']})
#app.route('/user-info')
def user_info():
if 'isLogged' in session:
return jsonify({'user': 'ali'})
else:
return jsonify({'error': 'Authentication error'})
and our front-end codes should be like this:
mounted() {
this.checkIsLogged();
},
methods: {
checkIsLogged() {
fetch('http://127.0.0.1:5000/user-info', {
mode: 'no-cors',
method: 'GET',
}).then((resp) => {
return resp;
}).then((obj) => {
if(obj.user) {
this.status = true
}
})
},
login() {
let frmData = new FormData(document.querySelector("#frmLogin"));
fetch('http://127.0.0.1:5000/login', {
mode: 'no-cors',
method: 'POST',
body: frmData,
}).then((resp) => {
return resp;
}).then((obj) => {
this.status = obj.status
})
}
}
Everything is normal until I refresh the page. When I refresh the page, I lose the sessions.
Server-side sessions are important for many reasons. If I use localStore or something like that how could be secure I have no idea.
I need some help who worked on similar projects. You can give me suggestions. Because I never worked similar projects.
Other stuff I've read on this topic:
Single page application with HttpOnly cookie-based authentication and session management
SPA best practices for authentication and session management
I'm still confused to about what can I do.
Session handling is something your SPA doesn't really care much about. The session is between the user-agent (browser) and the server. Your vue application doesn't have much to do with it. That's not to say you can't do something wrong, but usually the issue is not with your front end.
That being said it's tough do give an answer to this question because we don't really know what's wrong. What I can do is give you instructions on how you can diagnose this kind of problem. During this diagnosis you'll figure out where the actual issue is and, at least for me, it usually becomes obvious what I need to do.
Step 1)
Use some low level HTTP tool to check the Server response (personally I use curl or Postman when lazy). Send the login request to the server and take a look at the response headers.
When the login is successful you should have a header "Set-Cookie", usually with a content of a "sessionid" or whatever key you're using for sessions.
If you don't see a "Set-Cookie" one of the following is true:
Your server did not start a session and thus did not send a session cookie to the client
there's a proxy/firewall/anti-ad- or tracking plugin somewhere filtering out Cookies
If you see the Set-Cookie Header continue with Step 2, otherwise check the manual in regards to sessions in your chosen backend technology.
Step 2)
Thankfully most modern browsers have a developer console which allows you to do two things:
1) Check your HTTP request headers, body and response headers and body
2) Take a look at stored cookies
Using the first feature (in Chrome this would be under the "Network" tab in the developer console) diagnose the request and response. To do so you need to have the developer console open while performing the login in your app. Check the response of the login, it should contain the Set-Cookie if the login was successful.
If the cookie is not present your server doesn't send it, probably for security reasons (cross-origin policies).
If it is present, the cookie must now be present in the cookie store. In chrome developer console, go to the "Application" tab, expand Cookies from the left menu and take a look at the hosts for which cookies are present. There should be a cookie present which was set in the step before. If not the browser didn't accept the cookie. This usually happens when your cookie is set for a certain domain or path, which isn't the correct one. In such a case you can try to set the domain and/or path to an empty or the correct value (in case of the path a "/").
If your cookie is present, go to step 3
Step 3)
Remember when I said the app has nothing to do with the session. Every request you send either with ajax or simply entering a valid URL in the browser sends all cookies present for this host in the request headers. That is unless you actively prevent whatever library you're using to do so.
If your request doesn't contain the session cookie one of the following is usually true:
the usage of your http library actively prevents sending of cookies
you're sending a correct request but the cookie-domain/path doesn't match the request host/path and is thus not sent along
your cookie is super shortlived and has already expired
If your cookie is sent correctly then your sessions handling should work unless your server doesn't remember that session or starts a new session regardless of an existing session.
I realise this question is quite old and this extensive answer comes way too late, however someone with similar problems may be able to profit from it.
I want to use google apis in my app.
I successful get my access token but I am getting error :-
"Missing token endpoint URI."
My code is
def calender
client = Signet::OAuth2::Client.new(access_token: session[:access_token])
drive = Google::Apis::DriveV3::DriveService.new
drive.authorization = client
files = drive.list_files
end
when I printed my client variable, it showed my these details
#<Google::Apis::DriveV3::DriveService:0x0000010cc287f8
#root_url="https://www.googleapis.com/",
#base_path="drive/v3/",
#upload_path="upload/drive/v3/",
#batch_path="batch",
#client_options=#<struct Google::Apis::ClientOptions application_name="unknown", application_version="0.0.0", proxy_url=nil, use_net_http=false>,
#request_options=#<struct Google::Apis::RequestOptions
authorization=#<Signet::OAuth2::Client:0x0000010cc288c0
#authorization_uri=nil,
#token_credential_uri=nil,
#client_id=nil,
#client_secret=nil,
#code=nil,
#expires_at=nil,
#expires_in=nil,
#issued_at=nil,
#issuer=nil,
#password=nil,
#principal=nil,
#redirect_uri=nil,
#scope=nil,
#state=nil,
#username=nil,
#expiry=60,
#extension_parameters={},
#additional_parameters={},
#access_token="ya29.CjAbA8B7CFyhBLhFuEtP6kmCmuvJESwClkchiPpydjAqBOvDuvDERVCSVrYSSWLZvZc">, retries=0,
header=nil,
timeout_sec=nil,
open_timeout_sec=20>
I have spent two days to resolve this and explored whole internet but my issue is not resolved. My issue is related to already reported issue :-
Missing token endpoint URI while using a valid access_token
But solution provided in it is also not working for me. There is no attribute of "authentication" that I can use to assign my token.
I would greatly appreciate if someone help me with this.
When I create new request for WKWebView with authentication cookie and send the request, WKWebView correctly loads protected web page:
let req = NSMutableURLRequest(URL: NSURL(string: urlPath)!)
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies([myAuthCookie]);
req.allHTTPHeaderFields = headers;
webView.loadRequest(req)
The problem is, that when user clicks on a any link in the web page, with new request WKWebView loses authentication cookie and is redirected to logon page. Cookie domain and path are filled and correct.
I am aware of the missing functionality of WKWebView mentioned here.
Thanks in advance for any idea.
The best thing to do is to store your cookie into the
[NSHTTPCookieStorage sharedHTTPCookieStorage]
Then each time you want to load the request, call this function instead:
- (void)loadRequest:(NSURLRequest *)request {
if (request.URL) {
NSDictionary *cookies = [NSHTTPCookie requestHeaderFieldsWithCookies:[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL]];
if ([cookies objectForKey:#"Cookie"]) {
NSMutableURLRequest *mutableRequest = request.mutableCopy;
[mutableRequest addValue:cookies[#"Cookie"] forHTTPHeaderField:#"Cookie"];
request = mutableRequest;
}
}
[_wkWebView loadRequest:request];
}
It extract the right cookies from shared cookies and includes it into your request
I suppose when you set it in the request you are sending the cookie to the server but NOT setting it in the WKWebview. The cookies are usually set by the server in the "Set-Cookie" header and then it should be persisted. So if if you don't have an issue with cookie passing all the way to the server and back you can do a trick:
send the cookie in the first request
make the server send it back in the "Set-Cookie" header
every subsequent request should have the cookie
I haven't tried the approach yet but will be very surprised if it doesn't work.
The alternative as mentioned by Sebastien could be do inject it via javascript. Be mindful though that you cannot set "HTTP-Only" flag this way and the cookie will be available by all the scripts running (https://www.owasp.org/index.php/HttpOnly).
I'm still trying to find a natural way to set the cookie but I don't think it exists.
Hope it helps.
You can inject some javascript into the we view to load the cookies so that requests initiated by the web view will also have your cookies. See the answer to this question for more details:
https://stackoverflow.com/a/26577303/251687
I have the following NancyFX unit test.
var browser = new Browser(new UnitTestBootstrapper());
var response = browser.Post("/login", with =>
{
with.FormValue("UserName", userName);
with.FormValue("Password", password);
});
response.ShouldHaveRedirectedTo("/home");
You can see that I use an instance of Nancy.Testing.Browser to POST some form values. I would like to capture this Http request in Fiddler but I am not sure how to set-up the Browser (a proxy perhaps?)
Thanks
You can't because they never hit the network; that's the whole point of the browser class - to give you end to end testing without the performance hit/configuration issues of having to use hosting/http/networking/browser rendering.
If you want to go via the networking stack then use something like Selenium, or spin up a self host and poke it with EasyHttp or manually with HttpClient.