I'm using AppAuth to authenticate users via OpenId Connect but I'm unable to get passport to respond, let along validate the token.
These are the endpoints given at accounts.google.com/.well-known/openid-configuration:
authorization_endpoint "https://accounts.google.com/o/oauth2/v2/auth"
token_endpoint "https://oauth2.googleapis.com/token"
passport-google-oauth20 defaults to
https://accounts.google.com/o/oauth2/v2/auth
https://www.googleapis.com/oauth2/v4/token
I have an id_token and I've verified it's working at https://oauth2.googleapis.com/tokeninfo?id_token=XYZ.
https://www.googleapis.com/oauth2/v4/token?id_token=XYZ gives an empty response.
I've been trying combinations of passport-google-oauth, passport-oauth2, passport-google-oauth, these various google apis(did i mention https://openidconnect.googleapis.com/v1 etc?), and various headers(JWT, Bearer, etc) and POST params. In every case passport's strategy just silently fails.
I've tried adding some debug info via middleware as described here:
https://dmitryrogozhny.com/blog/easy-way-to-debug-passport-authentication-in-express
It doesn't help.
For the love of god, I've been bashing against this for 48 hours. Someone please help!!!
Related
I'm setting up a server with expressjs and keycloak-nodejs-connect, they are linked between them over common Storage for sessions. This works fine, ie, the flow with keycloak authentication its ok.
Now, I'm setting up a MQTT broker (Aedes) over server from expressjs. The unique authentication method in MQTT is username/password, then, I'm thinking about send the "token" (1) from webclient in the mqtt client connection flow in order to check on backend with keycloak-connect-nodejs if this token is valid.
I'm searching for some days and I cannot found a solution for this. How can i do? ie, verify the username received in the connection process on mqtt broker aginst keycloak over keycloak-connect-nodejs.
Or ... ¿are there other way to "link" mqtt authentication with my keycloak-session or express-session?
Thank you in advance.
(1) Which token should I use? From client I with keycloak.js I have the following token availables: idToken, token, subject, sessionId
Edit/Update with a solution
Several days later from starting my investigation, I have found the solution, my problem was that I'm trying authenticate into introspection endpoint with the accessToken, and I should do it with basic auth: client_name and client_secret. I have found the solution here: https://lists.jboss.org/pipermail/keycloak-user/2016-April/005869.html
I am sure someone out there has already done this, but I have yet to find any documentation with regard to the Microsoft implementation of JWT. The official documentation from Microsoft for their JWT library is basically an empty page, see:
https://learn.microsoft.com/en-us/dotnet/framework/security/json-web-token-handler-api-reference
So, here is what I (and I am sure many others) would like to accomplish:
Definition: User ID = The username or email address used to log into a system.
AUTHENTICATION:
A user logs in. The user fills in web form and the system sends (via HTTPS POST) the users ID and password (hashed) to the server in order to authenticate / validate the user.
Server Authenticates user. The users ID and password are checked against the values saved in the database and if NOT valid, an invalid login response is returned to the caller.
Create a JWT Token - ???? No documentation available!
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
Given the code below, can anyone provide a code example for steps 3 and 4?
[FunctionName( "authenticate" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get user ID and password from POST data
/*
* Step 2 - Verify user ID and password (compare against DB values)
* If user ID or password is not valid, return Invalid User response
*/
// Step 3 - Create JWT token - ????
// Step 4 - Return JWT token - ????
}
AUTHORIZATION:
Assuming the user was authenticated and now has a JWT token (I am assuming the JWT token is saved in the users session; if someone wants to provide more info, please do):
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
The JWT token is validated - ???? No documentation available!
If the JWT token is NOT valid, a BadRequest response is returned by the function.
If the JWT token is valid, the function uses the data passed to it to process and issue a response.
Given the code below, can anyone provide a code example for steps 1 and 2?
[FunctionName( "do_something" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get JWT token (from POST data or headers?)
// Step 2 - Validate the JWT token - ???
// Step 3 - If JWT token is not valid, return BadRequest response
// Step 4 - Process the request and return data as JSON
}
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Thanks in advance.
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Per my understanding, you could use the related library in your azure function code to generate / validate the JWT token. Here are some tutorials, you could refer to them:
Create and Consume JWT Tokens in C#.
Jwt.Net, a JWT (JSON Web Token) implementation for .NET
JWT Authentication for Asp.Net Web Api
Moreover, you could leverage App Service Authentication / Authorization to configure the function app level Authentication / Authorization. You could go to your Function App Settings, click "NETWORKING > Authentication / Authorization" under the Platform features tab. Enable App Service Authentication and choose Allow Anonymous requests (no action) as follows:
You could create a HttpTrigger function with anonymous accessing for user logging and return the JWT token if the user exists. For the protected REST APIs, you could follow the code sample below:
if(System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated)
{
//TODO: retrieve the username claim
return req.CreateResponse(HttpStatusCode.OK,(System.Security.Claims.ClaimsPrincipal.Current.Identity as ClaimsIdentity).Claims.Select(c => new { key = c.Type, value = c.Value }),"application/json");
}
else
{
return req.CreateResponse(HttpStatusCode.Unauthorized,"Access Denied!");
}
For generating the JWT token used in App Service Authentication, you could follow How to: Use custom authentication for your application and the code under custom API controller CustomAuthController from adrian hall's book about Custom Authentication to create the JWT token.
UPDATE:
For the custom authentication approach under App Service Authentication, I just want op to leverage the authentication / Authorization provided by EasyAuth. I have did some test for this approach and found it could work on my side. Op could send the username and password to the HttpTrigger for authentication, then the HttpTrigger backend need to validate the user info, and use Microsoft.Azure.Mobile.Server.Login package for issuing App Service Authentication token to the client, then the client could retrieve the token from the AuthenticationToken property. The subsequent requests against the protected APIs could look like as follows:
https://<your-funapp-name>.azurewebsites.net/api/<httpTrigger-functionName>
Header: x-zumo-auth:<AuthenticationToken>
NOTE:
For this approach, the related HttpTrigger functions need to allow anonymous accessing and the App Service Authentication also needs to choose Allow Anonymous requests (no action). Otherwise, the App Service Authentication and function level authentication would both validate the request. For the protected APIs, op needs to manually add the System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated checking.
Try this: https://liftcodeplay.com/2017/11/25/validating-auth0-jwt-tokens-in-azure-functions-aka-how-to-use-auth0-with-azure-functions/
I successfully made it work using this guide. It took awhile due to nuget versions.
Follow that guide properly and use the following nuget versions
IdentityModel.Protocols (2.1.4)
IdentityModel.Protocols.OpenIdConenct (2.1.4)
IdentityModel.Tokens.Jwt (5.1.4)
Oh and, the guide tells you to write your AUDIENCE as your api link, don't. You'll get unauthorized error. Just write the name of your api, e.g. myapi
If you get error about System.http.formatting not being loaded when running the function, try to reinstall NET.Sdk.Functions and ignore the warning about AspNet.WebApi.Client being restored using .NETFramework. And restart visual studio.
What you're describing is something that you should be able to do yourself by doing a little bit of research. To address your specific questions:
Create a JWT Token - ???? No documentation available!
The link Bruce gave you gives a nice example for how to create a JWT: https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
There's no documentation because you're basically inventing your own protocol. That means how you do it is entirely up to you and your application requirements. If it's a login action, it might make sense to return it as part of the HTTP response payload. Just make sure that you're using HTTPS so that the token stays protected over the wire.
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
How you send the token is, again, entirely up to you. Most platforms use the HTTP Authorization request header, but you don't have to if you don't want to.
The JWT token is validated - ???? No documentation available!
Use the ValidateToken method of the JwtSecurityTokenHandler (see the previous link for how to get the JwtSecurityTokenHandler). Docs here: https://msdn.microsoft.com/en-us/library/dn451155(v=vs.114).aspx.
I created an Azure Functions input binding for JWT Token Validation. You can use this as an extra parameter with the [JwtBinding] attribute. See https://hexmaster.nl/posts/az-func-jwt-validator-binding/ for source and NuGet package information.
Basically Azure Functions built on top of ASP.NET Core. By making some dependency injection tricks you could add your own authentication and policy-based authorization. I created demo solution with JWT authentication just for fun, beware to use it on production.
I am following this tutorial to enable jwt authentication in my express API.
https://jonathanmh.com/express-passport-json-web-token-jwt-authentication-beginners/
If I use a standard username/password authentication, I am able to use JwtStrategy to authenticate the JWT Token that I receive in the request header. jwt.sign() happens on the user id and secret. All of this works fine.
When I try to modify this code to verify the id_token (JWT Token signed using RS256) from OpenID Connect, then I get 401 Unauthorized no matter what. I tried to debug in the JwtStrategy method and it looks like the request doesn't even go inside that function. This id_token appears to be a lot longer than the one signed with HS256 algorithm.
A simple passport.authenticate call app.get('/callback', passport.authenticate('jwt', { session: false }), function(req, res, next) {
});
Can someone please explain why it doesn't even recognise my token?
It depends on how you are passing the token from client and reading it in server. The request will go into the validate function only if it receives the token correctly. Check similar post https://stackoverflow.com/a/46020083/4548946.
It worked for me. Hope it helps you too.
I am currently looking for a way to secure a REST API using token based authentication. I am developing the API in Python using Flask and have discovered the flask-security extension which seems to have a lot of interesting features.
One of the features mentioned in the documentation is Token Authentication.
According to the documentation:
Token based authentication is enabled by retrieving the user auth
token by performing an HTTP POST with the authentication details as
JSON data against the authentication endpoint. A successful call to
this endpoint will return the user’s ID and their authentication
token. This token can be used in subsequent requests to protected
resources.
I am however still a bit confused on how to implement this feature using flask-security.
Some online research has led me to using things such as #auth_token_required but I am having some trouble to put everything together. The flask-security documentation itself is not very helpful.
For example, how can a user get an authentication token? what is the authentication endpoints?
It would be great if you could lead me in the right direction. Code examples would be awesome too :-)
Endpoint is /login, you post your credentials as json request body:
{'email':'john#smit.com', 'password':'1234'}
However for this to work you need to disable the csrf tokens in your flask app (thanks Mandar Vaze):
app.config['WTF_CSRF_ENABLED'] = False
Then you do each request with the token in the HTTP headers:
Authentication-Token:WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Or as query string:
http://localhost:5000/protected?auth_token=WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Client example in python 3:
import requests
import json
#do the login
r = requests.post('http://localhost:5000/login',
data=json.dumps({'email':'john#smit.com', 'password':'1234'}),
headers={'content-type': 'application/json'})
response = r.json()
print(response) #check response
token = response['response']['user']['authentication_token'] #set token value
#Now you can do authorised calls
r = requests.get('http://localhost:5000/protected',
headers={'Authentication-Token': token})
print(r.text)
Angular example snippet to obtain the token:
$http.post('/login', {"email": $scope.formdata.login,"password":$scope.formdata.password}).
success(function(results) {
$window.sessionStorage.token = results.response.user.authentication_token;
});
Angular example snippet to visit protected pages:
if ($window.sessionStorage.getItem('token')) {
config.headers['Authentication-Token'] = $window.sessionStorage.getItem('token');
}
I found Flask-Security's token-based not a good candidate for my project. I recommend using JWT token instead.
The problems with Flask-Security's token based authentication.
Need to disable CSRF globally, this is not good when you also have a traditional web application in which CSRF token is desirable
No easy way to renew the token ( without submitting password again )
Can not control the payload of the token, there's no API to put/get data to/from the token
That token, by design, only works with one Flask app. So if your frontend app needs to talk with multiple restful apis, this wont work well
Check out JWT (pyjwt or flask-jwt) token, it solves all the above problems and more.
Authentication endpoint is /login
Look at the code of flask-security here specifically views.py: _render_json()
login() calls _render_json which in turn calls get_auth_token() - and returns the auth token.
Problem (for me) is to get this to work.
For me request.json seems empty (hence this does not work)
{"email": "test#example.com", "password": "test123"}
Hopefully this helps you move forward a little.
I suddenly started to receive the following error in my app. I'm sure it has been running fine before - atleast on my machine :-)
Error: Client side authentication flow with Google is not supported.
I get this error when I try to login using a accesstoken I've received from a gapi authorize call:
// login with google using gapi
gapi.auth.authorize({ client_id: clientId, scope: scopes, immediate: noPopup },
function (authResult) {
// Pass the accesstoken into azure
client.login("google", {"access_token": authResult.access_token}).then(
function(user) {
// logged into azure...
Then I receive the error about not supported flow.
(if I change from "google" to "facebook", the error is: Error: The Facebook Graph API access token authorization request failed with HTTP status code 400 - which makes sence since it's a google accesstoken I'm passing in)
If I paste in the url directly in a browser https://kjokken.azure-mobile.net/login/google, then everything seems to be ok.
Any ideas why this is happening?
Thanks for any help
Larsi
Thank you for using Mobile Services and taking the time to report this. We actively working on adding support for this particular scenario over the next couple of weeks, which explains what you are seeing. I will update this post when we have more information.
In the interim, did you consider using MobileServiceClient.login(MobileServiceAuthenticationProvider provider, UserAuthenticationCallback callback)?
Thanks,
-Yavor