Looking for advice on authentication and authorization - react-native

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"
}

Related

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.

Firebase createCustomToken() returns an invalid token in local emulators

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.

Understand how to also get an access token for down stream api access for web app with OneLogin

I've been at this for days and the documentation just isn't clear to me, maybe I'm just not reading it correctly.
I have a blazor WASM app (https://localhost:5001) that pulls data from an api. The api needs to be authenticated so I want to just pass the access token inside the header.
Inside the OneLogin admin dashboard I've created an OIDC app called "testApp", the Token Endpoint is None (PKCE).
Setting up oidcauthentication on blazor was super simple. I originall just used the
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("OneLogin", options.ProviderOptions);
})
However I quickly realized I had no way to add an audience. So I followed this guide ..
auth0 oidc for blazor
and this github for the actual code I modified to create a custom provideroptions that has an audience string
github repo
And I also had no issues setting it up. However, where I get stuck is how seemingly complicated OneLogin's side of the setup is.
Reading their docs onelogin api auth docs, there are no modern examples of setting it up past the postman import. Downloading the import file offers a fairly organized set of apis however I can't figure out what needs to go where.
First I created an Api Auth Server
{
"description": "API",
"configuration": {
"access_token_expiration_minutes": 20,
"refresh_token_expiration_minutes": 20,
"resource_identifier": "https://localhost:5005",
"audiences": [
"https://localhost:5005/worker",
"https://localhost:5005/user"
]
},
"name": "API"
}
then I created a scope
{ "value": "custom:scope",
"description": "A custom scope" }
then I added api auth server client. I went to the admin panel and grabbed the app id from the url. https://{domain}.onelogin.com/apps/{appId}/edit/#configuration
and added an api auth server
which gave me this back from the postman api
[
{
"name": "TestApp",
"app_id": 1111111,
"scopes": [
{
"id": 172,
"description": "A custom scope",
"value": "custom:scope"
}
],
"api_auth_id": 1246001
}]
So from this point it looks like I have everything I need? Except I still can't get it to create an access token. I go back to my application and use the modified service and add my audience to my appsettings.json
"OneLogin": {
"Authority": "https://{domain}.onelogin.com/oidc/2/",
"ClientId": "{clientId from onelogin}",
"ResponseType": "code",
"DefaultScopes": "openid profile groups",
"Audience": "https://localhost:5005"
Except it still doesn't add the extra audience to the access token causing my api calls to fail when I add the access token inside the header. If anyone can figure out where I've gone wrong I'd be incredibly grateful.
woot. Figured it out myself. I had everything right but I had the audience wrong. In their docs they discuss having multiple audiences like example.com/blah and example.com/bleh but having the audience as just example.com and then having different scopes PER web service actually is working fine.
So when I create example2.com and add it to the audience both my api's will be able to be accessed.

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.