How to get a firebase refresh token - firebase

In the documentation at https://firebase.google.com/docs/reference/rest/auth#section-refresh-token below this sample request curl
curl 'https://securetoken.googleapis.com/v1/token?key=[API_KEY]' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'grant_type=refresh_token&refresh_token=[REFRESH_TOKEN]'
it is mentioned that In the example above, you would replace [API_KEY] with the Web API Key of your Firebase project, [REFRESH_TOKEN] with the Firebase refresh token. I can get the API_KEY from https://console.cloud.google.com/apis/credentials
BUT where do I get this REFRESH_TOKEN from?
UPDATE: just realized (after a good night sleep) I had the following already in my page
const firebase = initializeApp(firebaseConfig);
const auth = getAuth(firebase);
...
auth.currentUser.getIdToken(false)
All I had to do was
auth.currentUser.refreshToken

The refresh_token is already included in the authentication API call response (whether it is SignInWithEmail, AnonymousSignIn, etc..).
You can consume this refresh token only once in order to get a new one.
It is your responsibility to save that refresh_token in order to consume it later.

Related

Identity Toolkit API config returns "CONFIGURATION_NOT_FOUND"

I am trying to enable Firebase Authentication in my project, and to add Phone Auth to it, via API (without using the GUI console).
I am using the Service Usage API in order to enable Identity Toolkit, and then trying to use Identity Toolkit API in order to add the Phone Auth.
I am enabling Identity Toolkit via the Service Usage API like this (POST request):
URL:
https://serviceusage.googleapis.com/v1/projects/MY_GCP_PROJ/services:batchEnable
Body:
{
"serviceIds": ["identitytoolkit"]
}
And indeed, after running this request I see in GCP console that Identity Toolkit has been enabled.
After that, I try to update the config using Identity Toolkit API, like this (PATCH request):
URL:
https://identitytoolkit.googleapis.com/v2/projects/MY_GCP_PROJ/config?updateMask=signIn
Body:
{
"signIn": {
"phoneNumber": {
"enabled": true,
"testPhoneNumbers": {
"+11111111111": "123456",
}
},
}
}
But for some reason, I receive an error saying:
{
"error": {
"code": 404,
"message": "CONFIGURATION_NOT_FOUND",
"status": "NOT_FOUND"
}
}
I can't understand why the Identity Toolkit API cannot find the configuration and update it as specified.
Does anyone know how it can be solved?
Thank you
I spent days config Firebase Auth without using Web UI :).
Even checking the GCP audit log to see what backend call enables Firebase Auth.
However, I could not find the CreateConfig method at https://cloud.google.com/identity-platform/docs/reference/rest.
I tried this method and things work.
https://cloud.google.com/identity-platform/docs/reference/rest/v2/projects.identityPlatform/initializeAuth
curl --request POST \
--url "https://identitytoolkit.googleapis.com/v2/projects/$ENV_GCP_PROJECT_ID/identityPlatform:initializeAuth" \
--header "Authorization: Bearer $TOKEN" \
--header 'Content-Type: application/json' \
--header "X-Goog-User-Project: $ENV_GCP_PROJECT_ID"
But the result is the new Identity Platform will be used instead of the old Identity Toolkit.
Looking at pricing, it seems (a bit) more expensive https://firebase.google.com/pricing.
I personally will use the new one (as Google is pushing it :).
Hope this answer somehow helps (or anyone can find the REST call to enable auth for the old Identity Toolkit)
The same issue happened to me when I was trying to use REST API but then I get to know that the URL I am using was wrong.
Try Method: projects.updateConfig

Google cloud (firebase) callable function 401: "unauthorized" error when called by http

I have simple test callable function deployed via firebase deploy --only functions.
Here it's content:
export const test = region('europe-west1').https.onCall((data, context) => {
logger.debug('test call info', data, context);
return 'hello, world!';
});
I can successfully call it by doing HTTP call to https://europe-west1-{project}.cloudfunctions.net/test and recieve {"result": "hello, world!"}.
Now want to protect this function via IAM policies.
I create new service account and load it's credentials json.
I go to console and remove from allUsers a Cloud Functions Invoker role and add service account created in #1 with Cloud Functions Invoker role.
<--- Now I recieve 403 Forbidden when I try to call my test function, as expected
I create id-token with my service account at my PC
const auth = new GoogleAuth({keyFile: './key.json'});
targetAudience = new URL('https://europe-west1-{project}.cloudfunctions.net/test');
const client = await auth.getIdTokenClient(targetAudience as string);
const idToken = await client.idTokenProvider.fetchIdToken(targetAudience as string);
console.log(idToken);
I verify my token is correct and issued for the right service account via https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={{id-token}}.
I call my endpoint with Authorization: Bearer {{id-token}} header.
I get 401 Unauthorized error with JSON telling me
{
"error": {
"message": "Unauthenticated",
"status": "UNAUTHENTICATED"
}
}
I'm in pain since after reading most of google cloud docs, SO (1, 2), etc. it seems that I do everything right but still get this error.
UPD1: providing additional info to #DazWilkin
1.
gcloud auth activate-service-account cloud-functions-invoker#{project-id}.iam.gserviceaccount.com --key-file="key.json"
Activated service account credentials for: [cloud-functions-invoker#{project-id}.iam.gserviceaccount.com]
gcloud projects get-iam-policy {project-id}
...
- members:
- serviceAccount:cloud-functions-admin#{project-id}.iam.gserviceaccount.com
- serviceAccount:cloud-functions-invoker#{project-id}.iam.gserviceaccount.com
role: roles/cloudfunctions.invoker
...
I copy this value gcloud auth print-identity-token | clip
Here is what I get after calling https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={{id-token}}
{
"aud": "32555940559.apps.googleusercontent.com",
"azp": "cloud-functions-invoker#{project-id}.iam.gserviceaccount.com",
"email": "cloud-functions-invoker#{project-id}.iam.gserviceaccount.com",
"email_verified": "true",
"exp": "1629157648",
"iat": "1629154048",
"iss": "https://accounts.google.com",
"sub": "114693730231812960252",
"alg": "RS256",
"kid": "6ef4bd908591f697a8a9b893b03e6a77eb04e51f",
"typ": "JWT"
}
I make this curl (copied from postman). I've also tried same curl with command-line - got same result.
curl --location --request POST 'https://europe-west1-{project-id}.cloudfunctions.net/test' \
--header 'Authorization: Bearer
{token}
' \
--header 'Content-Type: application/json' \
--data-raw '{
"data": {
"goodbye": "world:("
}
}'
UPD2: new input
This behaviour is observed only with callable functions https.onCall(). If I use https.onRequest() things work fine but I'm still confused about onCall behaviour, since it seems that I implement protocol correctly (see my curl).
OMG!!!!!
TL;DR: callable functions are only for end users authenticated with firebase auth and can't be used with IAM tokens. Only way to use them is with roles/cloudfunctions.invoker assigned to allUsers.
The thing is... I was looking into callable functions protocol specification here: https://firebase.google.com/docs/functions/callable-reference.
It says:
The HTTP request to a callable trigger endpoint must be a POST with the following headers:
...
Optional: Authorization: Bearer
A Firebase Authentication user ID token for the logged-in user making the request. The backend automatically verifies this token and makes it available in the handler's context. If the token is not valid, the request is rejected.
I was thinking specification means that we shall pass our service account id-token here and I was trying to do so (such as with onRequest functions). BUT SUDDENLY, token is interpreted differently there. It's a user token which is obtained through firebase auth. And it's even stated in the documentation one level deeper (1, 2):
Warning: The ID token verification methods included in the Firebase Admin SDKs are meant to verify ID tokens that come from the client SDKs, not the custom tokens that you create with the Admin SDKs. See Auth tokens for more information.
Missing this warning costed me 3 days of pain.

Firebase Storage REST API

I need very simple static image server for my flutter app. I am thinking about Cloud Storage, because I don't want to worry about own server administrating. I am using experimental Flutter for Desktop as tool for preparation data for mobile app, so I can use only REST API. I found out that Firebase Storage doesn't have own REST API and uses Google Cloud's one. To upload image to Cloud Storage I should make something like this:
curl -X POST --data-binary #[IMAGE_LOCATION] \
-H "Authorization: Bearer [OAUTH2_TOKEN]" \
-H "Content-Type: image/jpeg" \
"https://www.googleapis.com/upload/storage/v1/b/[BUCKET_NAME]/o?uploadType=media&name=[IMAGE_NAME]"
The problem is I can't understand how to get [OAUTH2_TOKEN] (access token) from my Dart code, and how to administrate my images (should I do something with Firebase Admin SDK?)
Could anyone help me, please?
I found answer to this question. First you need to create private key for service account in Firebase settings. Then use it to get access token using dart packages googleapis_auth and http.
var accountCredentials = ServiceAccountCredentials.fromJson({
"private_key_id": "<please fill in>",
"private_key": "<please fill in>",
"client_email": "<please fill in>#developer.gserviceaccount.com",
"client_id": "<please fill in>.apps.googleusercontent.com",
"type": "service_account"
});
var scopes = [
'https://www.googleapis.com/auth/cloud-platform',
];
var client = Client();
AccessCredentials credentials = await obtainAccessCredentialsViaServiceAccount(accountCredentials, scopes, client);
String accessToken = credentials.accessToken.data;
File image = File('path/to/image');
var request = Request(
'POST',
Uri.parse('https://storage.googleapis.com/upload/storage/v1/b/[BUCKET_NAME]/o?uploadType=media&name=images/$imageName'),
);
request.headers['Authorization'] = "Bearer $accessToken";
request.headers['Content-Type'] = "image/jpeg";
request.bodyBytes = await image.readAsBytes();
Response response = await Response.fromStream(await request.send());
print(response.statusCode);
client.close();
Get request you can make the similar way, but you have to encode firebase path to image:
var imagePath = 'images/img.jpg';
var encodedImagePath = Uri.encodeQueryComponent(imagePath);
var request = Request(
'GET',
Uri.parse('https://storage.googleapis.com/storage/v1/b/[BUCKET_NAME]/o/$encodedImagePath?alt=media'),
);
request.headers['Authorization'] = "Bearer $accessToken";
Google Cloud REST API: https://cloud.google.com/storage/docs/downloading-objects
The Firebase Storage REST API allows you to upload and download files from Cloud Storage using HTTP requests. You can use this API to build server-side applications that interact with Cloud Storage, or to integrate Cloud Storage into your existing server-side application.
To use the Firebase Storage REST API, you will need to have a Firebase project and a Cloud Storage bucket set up. You can set up a new Firebase project and Cloud Storage bucket by following the instructions in the Firebase documentation.
Once you have a Cloud Storage bucket set up, you can use the following HTTP methods to access and manipulate files in your bucket:
POST: To upload a new file to Cloud Storage, you can send a POST request to the /upload endpoint, along with the file data in the request body.
GET: To download a file from Cloud Storage, you can send a GET request to the /download endpoint, specifying the file's path in the bucket as a query parameter.
DELETE: To delete a file from Cloud Storage, you can send a DELETE request to the /delete endpoint, specifying the file's path in the bucket as a query parameter.
To authenticate your requests to the Firebase Storage REST API, you will need to provide a valid Firebase Authorization header with each request. You can generate this header using a JSON service account key file, which you can obtain from the Firebase console.
For more information about using the Firebase Storage REST API, including examples of how to make requests and handle responses, you can refer to the Firebase Storage REST documentation.
I hope this helps!

Which token is needed to send push notifications through POST

I'm trying to set up a REST API server that could send push notifications using Firebase. Google documentation says this is a valid POST request, as a start :
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message":{
"topic" : "foo-bar",
"notification" : {
"body" : "This is a Firebase Cloud Messaging Topic Message!",
"title" : "FCM Message",
}
}
}
However, I can't figure out which Authorization bearer is expected here. There is a ton of them on the firebase console, and I've tried each and every one of them, none work. They all result in 401 response.
Where can I find the expected bearer for this request ?
Thanks !
I find it easier to use legacy protocols to send push notifications. We just need the Server key which can be found in the Firebase Console.
Firebase Console > Project Settings > Cloud Messaging > Server Key
HTTP request looks like this:
curl -X POST -H "Authorization: key=<your_server_key>" -H "Content-Type: application/json" -d '{
"notification": {
"body" : "This is a Firebase Cloud Messaging Topic Message!",
"title" : "FCM Message",
},
"to": "/topics/<topic_name>"
}' "https://fcm.googleapis.com/fcm/send"
Check Server Reference for other APIs for server implementation.
So, first of all go to Google Cloud Console and choose APIs&Services->Credentials. From there click on +Create Credentials->OAuth Client ID (Interface changes all the time so try to find this option). And then, simply choose Add Key and it will give you a json file.
After you receive your json file you can try what was given in this guide: https://firebase.google.com/docs/cloud-messaging/auth-server.
If you want to send request from Postman then you can try https://developers.google.com/oauthplayground. Register there with your google account and from available services select Firebase Cloud Messaging API v1 -> https://www.googleapis.com/auth/firebase.messaging. There in the second step press Exchange authorization code for tokens. Finally, you will get your Access and Refresh Token there

ADFS 4.0 (2016) OpenID Connect userinfo endpoint returns 401 when provided with access token

Any ideas why this is. I have configured a Server Application and a Web API and an ID Token, Access Token & Refresh token is issued. However calling the userinfo endpoint return a 401 with the following header message:
WWW-Authenticate →Bearer error="invalid_token", error_description="MSIS9920: Received invalid UserInfo request. The access token in request is not valid."
The access token is valid according to http://jwt.io
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVVbEw5a1JocDJNLUVzTDlBRDJOQ055aHZtdyJ9.eyJhdWQiOiJ1cm46bWljcm9zb2Z0OnVzZXJpbmZvIiwiaXNzIjoiaHR0cDovL3Rlc3Rsb2dpbi51bm9wcy5vcmcvYWRmcy9zZXJ2aWNlcy90cnVzdCIsImlhdCI6MTQ4NjYyOTUxOSwiZXhwIjoxNDg2NjMzMTE5LCJhcHB0eXBlIjoiQ29uZmlkZW50aWFsIiwiYXBwaWQiOiJrbnVkIiwiYXV0aG1ldGhvZCI6InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOlBhc3N3b3JkUHJvdGVjdGVkVHJhbnNwb3J0IiwiYXV0aF90aW1lIjoiMjAxNy0wMi0wOVQwODozMjo1Ny4xNDZaIiwidmVyIjoiMS4wIiwic2NwIjoib3BlbmlkIiwic3ViIjoiM2krUGlyRncwSVlkdDVzTVNKQlpKbjVOTXZVWXZVdyt2WHI2Ujd1N0dBZz0ifQ.ajKtSk0xQE1crJkIA-lMLBZj2DtYE6xQo-Stmevh4pOGX17GEePbAFP-g6qPUwtGT_whVj74wRpSlyTBscp2JDsp_CW2E6BsTUI810S6jYRVjkYGxL1QcL1KoKJ8wyYKcxsCeOY2IUKNPnJOxV53Rs8E9EvJgjcsjTJHQw5Z_zC43dsTfCZvVfGrwJ3nn6BGxhIE_bEXvrWdgmg49V7-KK2kVDbDwJGr1iLpqU88-bkHdjGCIuc8XKX5pobWWlcyBmR_dpACM6Tu-d8jYJ_8mbof-eZrqn8YS61rgvRAhAAONyDklWcPgiYnhcMQVHZoCME-rVTjI6LDDY2czhL0rg
This question is asked long time ago but let me share my experience.
if you want to execute ADFS 4.0 userInfo endpoint(win server 2016) in a hope to get User profile but what i experienced is it return only Sub attribute
ex:
{
"sub": "MpR57wSIQz1kiR2uUMrkCQadbgDoztWmMV863Dugdso="
}
for anyone to try UserInfo endpoint you need to modify your application group, add api with Identitfier https://adfs.example.com/adfs/userinfo & at Client permission tab tick openId.
for execution of userinfo
Ex:
curl -X GET \
https://adfs.example.com/adfs/userinfo \
-H 'Authorization: Bearer ACCESS_TOKEN
Note: In your Acquire Accesstoken code you need to pass your resource = urn:microsoft:userinfo
The ADFS userinfo endpoint always returns the subject claim as
specified in the OpenID standards. AD FS does not provide additional
claims requested via the UserInfo endpoint. If you need additional
claims in ID token, refer to Custom ID Tokens in AD FS.
I've only done this once so I don't have much suggestions to make yet. So I cant make any suggested unless there is more detail.
You should try and get more evidence from the AD FS side. Enable debug logs using
wevtutil sl "ad fs tracing/debug" /l:5 /e:true
Do the repro and then disable logs as follows.
wevtutil sl "ad fs tracing/debug" /e:false
Then export the logs to view using
wevtutil epl "ad fs tracing/debug" c:\temp\userinfoerr.evtx
Open that event log in event viewer and have look and see what other errors are reported around validating the JWT.

Resources