Firebase createCustomToken() returns an invalid token in local emulators - firebase-authentication

I am using firebase authentication to handle user accounts for my web application. When a user enters valid login credentials I am using the firebase admin SDK to generate a JWT in a cloud function, which is sent back to the client and then authenticated with firebase. I am running into an issue where the JWT generated by the firebase admin SDK is invalid. More specifically, when the token is decoded (I used jwt.io), I get the following:
Header: {
"alg": "none",
"typ": "JWT"
}
Payload: {
"aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat": 1614367953,
"exp": 1614371553,
"iss": "firebase-auth-emulator#example.com",
"sub": "firebase-auth-emulator#example.com",
"uid": "some uid here"
}
The token is not only missing a signature, but the iss and sub values are wrong. I am using admin.auth().createCustomToken(uid) to generate the token and the app is being initialized with a valid service account that has Service Token Creation privileges.
EDIT:
I have just figured out that the token is generated incorrectly only while everything is run locally using firebase emulators. When I deploy the app, the token is generated and validated just fine.

Make sure you are instrumenting your app to talk to the authentication emulator ... and doing it before the authentication listeners do their thing.

Related

Looking for advice on authentication and authorization

I am building a mobile application with react native + expo. I am using Redux for my client state. React query for server state.
On login using a username and password I fetch access token. I store that token in redux store and use the useSelector() hook to grab token from store and pass it in my API calls. On logout I clear out my store.
I am under the impression that this is a security flaw for my token to be stored unencrypted in the client side code.
My solution is to refactor my application to use Expo Secure Store. Which allows me to store encrypted token in keychain services(ios) and sharedPreferences(android). Where I could retrieve token value using a key and thus removing the actual token from my client side code.
Does this solution make sense? Hoping someone can confirm before I refactor my whole app. Thanks in advance!
This is how you can define exp of token in claims
{"typ":"JWT","alg":"ES256","kid":"1"}.{
"aud": ["https://xyz/"],
"iss": "https://xyz/authserver/v1",
"sub": "abc",
"sys": "abc",
"exp": 1675943895,
"iat": 1675943295,
"jti": "5656757",
"scp": "example",
"roles": ["any"],
"ver": "1.0.0"
}

Tapkey Token Exchange returns access token for invalid user

regarding tapkey token exchange flow: when exchanging a jwt token for an access token through https://login.tapkey.com/connect/token api, I get an access token response, even the user does not exist.
My jwt token contains of the following: Header:
{
"alg": "RS256"
}
Payload:
{
"algorithm": "RS256",
"aud": "local",
"iat": 1633339589,
"exp": 1633343189,
"iss": "tapkey",
"sub": "NOT_EXISTING_USER_ID"
}
this raises the following questions:
when I create an IdentityProviderUser I get in return an id and an ipUserId.
Should the jwt-token's "sub" be the returned id or should "sub" be the returned ipUserId?
In both cases I am able to retrieve an access token, because regardless what I define in "sub" an access token is exchanged.
what happens when mobile tries to login with a not existing user's access token?
For the token exchange itself it does not matter if the user already exists or not. It just validates your signed token and exchanges it with a token for the tapkey system.
The subject of your jwt token should be your assigned userId (= ipUserId) which also was/will be used to create the user:
https://developers.tapkey.io/api/ip_users/#create-identity-provider-user
Ad 2:
By default when a mobile tries to login in the tapkey mobile sdk with a token with an id, which was not created yet, will cause an error.

Call azure function secured by AAD using client id and client secret

I have an Azure Function secured by the Azure Active Directory.
I can successfully call the application from the browser provided that I'm logged.
Now, what I want to do is to call that function from an application that doesn't use the username and password in order to authenticate but rather a trusted application client id and client secret.
I tried to use for that purpose the same application (say ApplicationA) that has been created for securing the function application.
I went to the App Registrations, found the application created by configuring the Azure Active Directory authentication provider in the Function App Authentication/Authorization settings (ApplicationA) and I set a Client Secret for it.
Now I'm able to obtain a token using said application Client Id and the generated secret.
But when I'm trying to call the Function using that token I'm getting 401 error.
I tried the same operation with a newly created application in App Registration (say ApplicationB) but with the same result, I'm still getting 401.
I even tried to add a Reader Role for that application in Subscriptions but then again - 401 when calling Function with the token.
I know, there's something like API permissions in the application settings.
So I tried to add the permission for ApplicationB to ApplicationA user_impersonation but it also doesn't work so that's not the way.
So how do I grant the permission for a registered Application for which I'm able to acquire a token so I can use this token to call the Function?
EDIT:
I'm using the following code for token acquisition:
using Microsoft.Identity.Client;
string ClientId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
string ClientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string TenantId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
string Authority = $"https://login.microsoftonline.com/{TenantId}";
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithClientSecret(ClientSecret)
.WithAuthority(new Uri(Authority))
.Build();
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
string token = result.AccessToken;
You need to register at least one application permission (appRole with allowed member type Application) via the manifest into the functions app registration.
Then you can assign the application permission to the client app.
You can see my article for more info on defining permissions: https://joonasw.net/view/defining-permissions-and-roles-in-aad
Example app permission in manifest:
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Allow the application to read all things as itself.",
"displayName": "Read all things",
"id": "32028ccd-3212-4f39-3212-beabd6787d81",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Things.Read.All"
}
],
You need to define the id yourself, it just needs to be a GUID.
The value is what is sent in the tokens in the roles claim.
Description and display name are just for how the permissions shows up in the UI.

How do you refresh a JWT Token when the user authenticated with Cognito Hosted UI in AWS?

Details first:
Environment = Cognito Hosted UI
Situation = User signs in using it
Result = He's successfully authenticated and is redirected to whatever URL to which AWS adds the parameter "id_token=" with whatever value
Sample whatever value after decrypting that token with jwt.io =
{
"at_hash": "some_value_here",
"sub": "the_sub_id_in_cognito",
"aud": "the_client_id_of_the_cognito_app",
"email_verified": true,
"token_use": "id",
"auth_time": 1573661803,
"iss": "https://cognito-idp.us-east-1.amazonaws.com/AWSRegion_CognitoPoolName",
"name": "FirstName LastName",
"cognito:username": "the_username_in_cognito",
"exp": 1573665403,
"iat": 1573661803,
"email": "the_email_in_cognito"
}
My question = This token expires within one hour (you can't change this). And in order to keep the user authenticated for more than one hour, you'd have to submit a refresh token using the Cognito InitiateAuth API.
All fine and dandy, except I don't see any refresh token in that JSON :|
Where do I get that refresh token value ? Is it something that gets generated once (and once only) at initial user registration and I should store it in some database ?
Or is that token NOT generated by Cognito Hosted UI because it's not supported and I should stop using it altogether ?
PS: On a different note -> Is Cognito Hosted UI any good or is it bull-crap and I should stop looking into it altogether ?
Thanks and hope you can help me on this ...
Marius
Update.
I've changed my logic to continue to use Cognito Hosted UI and "generate" the HTML pages from Lambda.
I've used the logic from here -> https://github.com/aws/chalice/issues/717 to fetch the authentication code and store them as JWT tokens in cookies using Lambda.
I've also had to modify the App Client Settings in Cognito as following:
Allowed OAuth Flows = Just Authorization code grant
Basically the logic of using JWT tokens now is being generated "manually" at the Lambda layer.
Hope this helps someone out there...

How to refresh the access token of an Application with the WSO2 API Manager 1.10.0?

I've (finally) managed to get a valid access token for an application using the API with the WSO2 API Manager 1.10.0. However, it is unclear to me how to refresh this token.
I got the working access token by calling https://myapi.mydomain.com/api/am/store/v0.9/applications/generate-keys?applicationId=2b205ee5-5891-4913-96e0-b4952d7d2a4c with the following payload
var payload = {
'grant_type': 'password',
'username': username,
'password': password,
"validityTime": validityTime,
"keyType": "PRODUCTION",
"accessAllowDomains": [ domain ]
}
The result looks like this:
Generating application keys for application with id '2b205ee5-5891-4913-96e0-b4952d7d2a4c'
{ consumerKey: '5k7UDuFTV0UE7mESHerEIm2Nj3ga',
consumerSecret: 'm1hS_SNfHF25l9lP9YjYpf977VUa',
keyState: 'APPROVED',
keyType: 'PRODUCTION',
supportedGrantTypes:
[ 'urn:ietf:params:oauth:grant-type:saml2-bearer',
'iwa:ntlm',
'refresh_token',
'client_credentials',
'password' ],
token:
{ tokenScopes: [ 'am_application_scope', 'default' ],
validityTime: 2678400,
accessToken: 'be8661550ee51b7682902e58a58108f6' } }
So it does seem like I have the grant to refresh my access token. Howver the documentation only mentions how to do this when you have a refresh token, which is missing from the reply. What am I doing wrong?
The API you used to generate tokens is not the API for your job. The API 'applications/generate-keys' is there to generate application related keys (Client secret and client id) . The token generated for
this has a client_credential grant type. thats why you do not get a refresh token. That token is generated using the client id and secret.
I see you have sent the grant type as 'password' in the payload but those parameters are not valid to start with. that api does not accept grant type name. (api is there to generate the application keys. so grant type is not needed)
Actual sample payload (see https://docs.wso2.com/display/AM1100/apidocs/store/#!/operations#ApplicationindividualApi#applicationsGenerateKeysPost)
{
"validityTime": "3600",
"keyType": "PRODUCTION",
"accessAllowDomains": ["ALL"
]
}
to generate the tokens please use the token api (https://docs.wso2.com/display/AM1100/Token+API). Those apis are implemented according to the OAuth2 specs. You will get a refresh token when you use 'password'
grant type using these token apis
You can refresh the token in API Store (developer portal), if you click on the Subscriptions tab, and there either:
Manually click the Re-generate button refresh right now, or
Click the cURL button to generate the command that you can use to refresh programmatically:
Notes:
You can also read more information about Token API in documentation,
For the screenshot, I used hosted version of API Manager - WSO2 API Cloud.