I'm a newbie so any help appreciated.
I've created an app/service using Google App Engine (node) that returns a simple 'hello world' response, see https://resumetemplatesconverter.appspot.com/
I've also got a Polymer web app that uses Firebase Authentication for sign up, sign in, sign out, etc.
Question is, what is the best way to configure the Google App Engine app/service so that only users authenticated with the Polymer web app can use it?
Thanks.
Firebase (Authorization Server) sends a token (Access Token) back to the client (browser).
The client now makes a request to your app engine service (Resource Server) with that token.
What you need to do is to check if the token is valid and if it is valid, return that secret data.
The OAuth 2.0 spec doesn't clearly define the interaction between a Resource Server and Authorization Server for access token validation:
Access token attributes and the methods used to access protected resources are beyond the scope of this specification and are defined by companion specifications.
So for each authentication service (Google, Facebook, GitHub, etc.) you use, you have to look up how to validate the Access Token.
Example:
Google
Request (from your app engine backend)
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123
Response
{
// These six fields are included in all Google ID Tokens.
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"iat": "1433978353",
"exp": "1433981953",
// These seven fields are only included when the user has granted the "profile" and
// "email" OAuth scopes to the application.
"email": "testuser#gmail.com",
"email_verified": "true",
"name" : "Test User",
"picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
"given_name": "Test",
"family_name": "User",
"locale": "en"
}
You can make this plain request from your backend server but it would be better using one of the Google API Client Libraries
See here for more info regarding Authenticate with a backend server
Related
I am writing a custom backend (nestjs) in which I want to verify if the token from firebase auth is valid and retrieve user information too.
I do not want to use the actual firebase auth so I ended up using firebase local emulator.
Now I want to test my endpoint written in nestjs using postman wherein I send the unsigned token from postman for nestjs to verify from local emulator. But I couldn't find a way to create an unsigned token without creating a UI for the same, I really do not want to spend time in creating a react application to just console.log a token. Is there any better way to do this that I might be missing ??
Thanks for the help.
Assuming your Authentication emulator runs on port 9099 and you have a user created, you should be able to make the following HTTP POST request to get a token. The token is in the idToken field of the response object.
http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=any_key_you_want
Body (JSON):
{
"email": "your-user#mail.com",
"password": "some-password"
}
Response:
{
"kind": "identitytoolkit#VerifyPasswordResponse",
"registered": true,
"localId": "yourUserId",
"email": "your-user#mail.com",
"idToken": "someIdToken",
"refreshToken": "someRefreshToken",
"expiresIn": "3600"
}
I found this solution playing with a React application with the firebase (^9.6.2) package installed, setting connectAuthEmulator(auth, "http://localhost:9099");, and looking at the request it made when I logged in.
Does the Smart Device Management API support access using a Service Account? If so what's the magic combo?
I can access the API using registered OAuth2, and get valid device list response.
When using Service Account credentials to access the device list API I get:
{
"error": {
"code": 404,
"message": "Enterprise enterprises/{project-id} not found.",
"status": "NOT_FOUND"
}
}
I think the problem is that google have chosen to cut off the "home project" user. They seem to only support oauth2 auth and if you want to use it you have to get your app certified, otherwise they revoke the refresh token after 7 days. If the refresh token didn't get revoked every 7 days then I'd be happy with oauth2 offline auth. Come on google, support the home hobbyists!
I have a scenario where I need to do a secure request a Firebase Cloud Function from an external server using a HTTP request. In order to request it I need to send a bearer JWT token on the authorization header. After sometime looking at the Google documents to Firebase/GCP I've found many different ways to authenticate using google different APIs, but I'm kinda lost on it.
I know that I need to use a service account in order to identify the machine that is calling instead a common human-user credentials. I also know that the service account provides a JSON file that contains secure information to identify that service account, like the private key. By looking different docs I found this one that explains how to generate and request a token. After following those steps, I'm facing a 403 status when I try to call the cloud function using the resulting token.
I doubled checked the roles my service account has and I do have the ones the docs have pointed me.
Does anyone knows or have any suggestions how to proceed to have cloud function authorized calls by a machine (not human) interaction.
Edit 1:
As requested here I'm posting my JWT generator code:
const {
private_key_id,
private_key,
client_email,
} = require('./serviceAccount.json');
const jwt = require('jsonwebtoken');
const payload = {
"kid": private_key_id,
"iss": client_email,
"sub": client_email,
"iat": 1611257400,
"exp": 1611260940,
"aud": "https://oauth2.googleapis.com/token",
"target_audience": "https://<project- region>.cloudfunctions.net/helloWorld"
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256', header: {"alg":"RS256","typ":"JWT"} });
console.log(token);
With the result token from above I'm sending a POST request to https://oauth2.googleapis.com/token where the token is sent as the assertion field on a form data.
After suggestions here I did some research and found this blog with instructions to generate a Identity token using my service account. So I ran:
# Load the service account identity
gcloud auth activate-service-account --key-file=key.json
# Generate an id token
gcloud auth print-identity-token
The resulting token gave me the same result a 403 - Forbidden error. The interesting part is that using my user credentials and using gcloud to generate an identity token I was able to request the Cloud function with a 200 result.
I'm thinking that I'm missing some sort of role/privilege/scope on my service account configuration.
Make sure that the service account has assigned the cloudfunctions.functions.invoke in order to guarantee that the Cloud Function can be triggered from an external server using an HTTP request.
I am developing the backend for a mobile app using Google App Engine Standard Environment (Python) and Cloud Endpoints with Firebase for authentication. This backend needs to connect to a frontend created with Unity.
I am having trouble with Cloud Endpoints reading the authentication token being sent from the Unity frontend after logging in to Firebase. The App Engine logs state "No auth token is attached to the request" with each attempt at sending an authenticated request.
Here is the Cloud Endpoints declaration that includes Firebase as an issuer in my main Python file:
#endpoints.api(name='connected',
version='v4.4.0',
allowed_client_ids=["32366828803-g14dan8j9m1dhises6namb5vpebopgpd.apps.googleusercontent.com "],
issuers={'firebase': endpoints.Issuer('https://securetoken.google.com/fleet-fortress-211105',
'https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com')})
Here is the end of the swagger.yaml file that has the security definitions:
securityDefinitions:
firebase:
authorizationUrl: ''
flow: implicit
type: oauth2
x-google-issuer: 'https://securetoken.google.com/fleet-fortress-211105'
x-google-jwks_uri: 'https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com'
x-google-audiences: "32366828803-g14dan8j9m1dhises6namb5vpebopgpd.apps.googleusercontent.com"
security:
- firebase: []
I am sending the auth token that was received from Firebase to my Cloud Endpoints API in the Authorization header (e.g. Authorization:Bearer {token}).
Headers being sent:
request headers
Decoded JWT being sent in authorization header as Bearer:
{
"iss": "https://securetoken.google.com/fleet-fortress-211105",
"aud": "fleet-fortress-211105",
"auth_time": 1533831541,
"user_id": "8VdGVw9cF8V9QtfIZpgnD4DHKsY2",
"sub": "8VdGVw9cF8V9QtfIZpgnD4DHKsY2",
"iat": 1533831566,
"exp": 1533835166,
"email": "XXXX#gmail.com",
"email_verified": false,
"firebase": {
"identities": {
"email": [
"XXXX#gmail.com"
]
},
"sign_in_provider": "password"
}
}
Any help in getting my GAE Cloud Endpoints backend to read the authorization header for a JWT is greatly appreciated.
I don't know why that error is getting logged; the authorization header properly contains a Bearer token, which is what's required.
However, that error message shouldn't actually stop authentication from working. (The authentication system in the Python Frameworks is kind of a mess and there are two parallel mostly-working implementations.)
Instead, you need to call endpoints.get_current_user() in each method that you want to be protected.
I obtain an access_token and id_token from AzureAD for my app, which is using OAuth2 with the implicit flow. This is a sample URL where I obtain the tokens:
https://login.microsoftonline.com/my_tenant_id/oauth2/v2.0/authorize?response_type=id_token+token&client_id=my_client_id&state=some_state&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fsign-in&scope=openid%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read&nonce=some_nonce
The scope is openid https://grap.microsoft.com/user.read.
The response_type is id_token+token.
I also have a Asp.Net backend, I want to secure. So I use the Authorize Attribute for my controller and send a token in the header as like this: "Authentication : Bearer THE_TOKEN".
My configuration in Startup.cs looks like this:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = string.Format("https://login.microsoftonline.com/{0}/v2.0/",
"d67853c3-db96-4dac-a37b-f2bfb12b42d1"),
Audience = "8422b3fb-5612-4fdd-a90f-707d7218de57"
});
From what I have read, the access token should be used for this, and the id_token should not leave the frontend. But authentication in the backend only works with the id token in my case. The access_token can not be signed Bearer error="invalid_token", error_description="The signature is invalid".
Looking at the access_token in jwt.io, I see the tokens have different audiences and issuers. The access_token for example has this
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/d67853c3-db96-4dac-a37b-f2bfb12b42d1/",
whereas the id token has this
"aud": "my_client_id",
"iss": "https://login.microsoftonline.com/my_tenant_id/v2.0",
So it seems to me, the access_token was somehow issued for the Graph API. Would be glad if someone could tell me, what i am doing wrong or how I can try to solve my issues.
edit:
It WAS working as intended before when I used the scope openid profile. But due to changes in Azure, this scope is not valid anymore and Microsoft directed me to use the scope mentioned above.
As you mentioned, the access token you requested is for the Microsoft Graph. And the id_token is only for the client to authenticate the user instead of for the resource server.
To protect the web API using the Azure AD V2.0 endpoint, we can acquire the access token for the web API like request below:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=token&client_id={client_id}&scope=api://{client_id}/access_as_user&redirect_uri={redirect_uri}
And here is the code using protecting the web API via Azure AD V2.0 endpoint:
public void ConfigureAuth(IAppBuilder app)
{
System.Diagnostics.Trace.TraceWarning("Hello");
var tvps = new TokenValidationParameters
{
// The web app and the service are sharing the same clientId
ValidAudience = clientId,
ValidateIssuer = false,
};
// NOTE: The usual WindowsAzureActiveDirectoryBearerAuthenticaitonMiddleware uses a
// metadata endpoint which is not supported by the v2.0 endpoint. Instead, this
// OpenIdConenctCachingSecurityTokenProvider can be used to fetch & use the OpenIdConnect
// metadata document.
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")),
});
}
}
More detail about protecting the web API via Azure AD V2.0 endpoint, you can refer the document below:
Calling a web API from a .NET web app