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

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...

Related

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.

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.

django rest framework - token authentication logout

I have implemented the Token Authentication according to the django rest framework Docs.
Form what I read, the Token Authentication of DRF is quite simple - one token per user, the token doesn't expire and is valid for use always (am I right?).
I understand that there are better practices out there, but for now the DRF token authentication is fine for me.
my question is- what is the best practice for logout with the normal DRF token authentication?
I mean, when the user logs out, should I delete the token from the client side? and then on login get the token again? should I delete the token and generate a new one?
Anyone with experience with this?
Here's a simple view that I'm using to log out:
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
class Logout(APIView):
def get(self, request, format=None):
# simply delete the token to force a login
request.user.auth_token.delete()
return Response(status=status.HTTP_200_OK)
Then add it to your urls.py:
urlpatterns = [
...
url(r'^logout/', Logout.as_view()),
]
WHOLE IDEA OF TOKEN AUTHENTICATION:
Normally in authentication services, there is a lifetime associated with a token. After a specific time, the token will get expired. Here, we get an access token which has an expiry time sent along with it by the server. Now the client needs to send this token everytime in the request header so that the server can identify who the user is. Either we can keep track of when it expires or we can just keep using it until we get an INVALID_TOKEN error. In that case we would have to again get the token from the server.
The lifetime of the access_token is independent of the login session of a user who grants access to a client. OAuth2,lets say, has no concept of a user login or logout, or a session. The token is just used to identify the user if he is who he says he is.
The token is unique for a user and client. You may save it to cookies to enable something like remember me but on the server you don't need to delete it. Whenever the token expires, the client need to send a request to the server to obtain the token again.
Token Expiry in DRF Token Authetication:
Currently, DRF Token authentication does not support this functionality. You would have to implement it yourself or use a third party package which provides this functionality. It should check for token expiry and raise an exception if the token has expired.
To implement it yourself, you can subclass from the DRF Token Authentication class and add your logic.
You can even use a third-party package django-rest-framework-expiring-tokens.
Some References:
1. Token Authentication for RESTful API: should the token be periodically changed?
2. How to Logout of an Application Where I Used OAuth2 To Login With Google?
It sounds like SessionAuthentication is what you are really looking. You can start(login) a session via BasicAuthentication or TokenAuthentication. Then use sessionid as your "token" for the rest of api calls. The "token" expires when you logout or exceed certain timing.
If you run into csrftoken issue using session authentication, this could be a very helpful.

Can I auto login a user on the client that has already been authorized on the server?

I have an application that uses google's oauth system to authorize with youtube's api. The code for this is done on our server and we receive tokens without any problem. We'd like to move some of the api calls to the client using their javascript api.
Since we've already authorized the user with the correct scopes required for the youtube api (https://www.googleapis.com/auth/youtube) I assumed when I called authorize on the client it would know that my application was already authorized and allow auto login. Instead I receive a "immediate_failed" response. Does anyone know why? Thanks!
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
If you have the token, you can just use setToken instead of going through OAuth2 again.

Google Drive API accessing both "online" and "offline" at the same time

This is a follow up to my previous question: How do I access Google Drive Application Data from a remote server?
I have an application which needs to access Google Drive AppFolder both client-side (online, JavaScript) and server-side (offline, Python). My application is unique in that the client and the server may not be able to communicate past the original authentication.
Thus, I use the following to obtain an auth token for the server (initiated client-side):
gapi.auth.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES,
'access_type': 'offline',
'response_type': 'code',
'state': 'my_state',
}, null, 2),
'redirect_uri': 'http://server/oauth2callback',
'immediate': false
},
handleOfflineAuthResult);
the server stores the credentials including refresh token.
Then the client (in a subsequent user session) sends requests directly to Google Drive for token:
gapi.auth.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES,
'immediate': true
}, handleAuthResult);
now when the client does that it gets a refresh token but invalidates the refresh_token for the server. Thus my server can no longer refresh its token and gets 'AccessTokenRefreshError: invalid_grant'.
Is there any way to solve this problem assuming the client and the server cannot communicate past the original authentication (i.e. the client can't just ask the server for its auth_token, that's by design) ?
The only "solution" I have thought of is to have the client store its auth_token and refresh_token in the AppFolder and the server continuously pull the AppFolder for new credentials, subsequently replacing its copy with the client one.
You say
when the client does that [calls gapi.auth.authorize] it gets a refresh token but invalidates the
refresh_token for the server
At least the first part is incorrect, and I suspect the second part is too. gapi.auth.authorize returns an access token, not a refresh token (see https://developers.google.com/api-client-library/javascript/reference/referencedocs#OAuth20TokenObject).
I doubt very much that requesting an access token for your client is invalidating a refresh token for your server. If you are 100% sure that it is, you should use a separate client ID for each of your JS and web client apps. Note that a JS client will never use a refresh token, as this would be a major security flaw. JS clients always request access tokens as needed, either from your server or from Google.