Skip to content

Commit

Permalink
Rename expires in to expires at (#688)
Browse files Browse the repository at this point in the history
Co-authored-by: Rita Zerrizuela <[email protected]>
  • Loading branch information
poovamraj and Widcket authored Aug 10, 2023
1 parent 47b34b2 commit ac5d835
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 63 deletions.
3 changes: 2 additions & 1 deletion MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

- The properties inside the `user` object will now be camelCase instead of snake_case
- Removed the `type` property returned in the `Credentials` object in Android. Use `tokenType` instead.
- `Credentials` object in Android will return `expiresIn` instead of `expiresAt`
- `Credentials` object in iOS will return `expiresAt` instead of `expiresIn`
- `expiresIn` value will now return `expiresAt` value which is a UNIX timestamp of the expiration time.
- `max_age` parameter is changed to `maxAge` in `WebAuth.authorize()`
- `skipLegacyListener` has been removed in `authorize` and `clearSession`
- `customScheme` is now part of `ClearSessionOptions` instead of `ClearSessionParameters` in `clearSession`
Expand Down
22 changes: 3 additions & 19 deletions android/src/main/java/com/auth0/react/CredentialsParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ public class CredentialsParser {
private static final String SCOPE = "scope";
private static final String REFRESH_TOKEN_KEY = "refreshToken";
private static final String TOKEN_TYPE_KEY = "tokenType";
private static final String EXPIRES_IN_KEY = "expiresIn";
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

public static ReadableMap toMap(Credentials credentials) {
WritableNativeMap map = new WritableNativeMap();
map.putString(ACCESS_TOKEN_KEY, credentials.getAccessToken());
map.putDouble(EXPIRES_IN_KEY, credentials.getExpiresAt().getTime());
map.putDouble(EXPIRES_AT_KEY, credentials.getExpiresAt().getTime() / 1000);
map.putString(ID_TOKEN_KEY, credentials.getIdToken());
map.putString(SCOPE, credentials.getScope());
map.putString(REFRESH_TOKEN_KEY, credentials.getRefreshToken());
Expand All @@ -38,23 +37,8 @@ public static Credentials fromMap(ReadableMap map) {
String tokenType = map.getString(TOKEN_TYPE_KEY);
String refreshToken = map.getString(REFRESH_TOKEN_KEY);
String scope = map.getString(SCOPE);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, Locale.US);
Date expiresAt = null;
String expiresAtText = map.getString(EXPIRES_AT_KEY);
if(expiresAtText != null) {
try {
expiresAt = sdf.parse(expiresAtText);
} catch (ParseException e) {
throw new CredentialsManagerException("Invalid date format - "+expiresAtText, e);
}
}
double expiresIn = 0;
if(map.hasKey(EXPIRES_IN_KEY)) {
expiresIn = map.getDouble(EXPIRES_IN_KEY);
}
if (expiresAt == null && expiresIn != 0) {
expiresAt = new Date((long) (System.currentTimeMillis() + expiresIn * 1000));
}
Double expiresAtUnix = map.getDouble(EXPIRES_AT_KEY);
Date expiresAt = new Date(expiresAtUnix.longValue() * 1000);
return new Credentials(
idToken,
accessToken,
Expand Down
9 changes: 4 additions & 5 deletions ios/NativeBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public class NativeBridge: NSObject {
static let refreshTokenKey = "refreshToken";
static let typeKey = "type";
static let tokenTypeKey = "tokenType";
static let expiresInKey = "expiresIn";
static let dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

static let credentialsManagerErrorCode = "a0.invalid_state.credential_manager_exception"
Expand Down Expand Up @@ -108,11 +107,11 @@ public class NativeBridge: NSObject {
let refreshToken = credentialsDict[NativeBridge.refreshTokenKey] as? String
let scope = credentialsDict[NativeBridge.scopeKey] as? String
var expiresIn: Date?
if let string = credentialsDict[NativeBridge.expiresInKey] as? String, let double = Double(string) {
if let string = credentialsDict[NativeBridge.expiresAtKey] as? String, let double = Double(string) {
expiresIn = Date(timeIntervalSince1970: double)
} else if let double = credentialsDict[NativeBridge.expiresInKey] as? Double {
} else if let double = credentialsDict[NativeBridge.expiresAtKey] as? Double {
expiresIn = Date(timeIntervalSince1970: double)
} else if let dateStr = credentialsDict[NativeBridge.expiresInKey] as? String {
} else if let dateStr = credentialsDict[NativeBridge.expiresAtKey] as? String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = NativeBridge.dateFormat
expiresIn = dateFormatter.date(from: dateStr)
Expand Down Expand Up @@ -185,7 +184,7 @@ extension Credentials {
NativeBridge.tokenTypeKey: self.tokenType,
NativeBridge.idTokenKey: self.idToken,
NativeBridge.refreshTokenKey: self.refreshToken as Any,
NativeBridge.expiresInKey: floor(self.expiresIn.timeIntervalSince1970),
NativeBridge.expiresAtKey: floor(self.expiresIn.timeIntervalSince1970),
NativeBridge.scopeKey: self.scope as Any
]
}
Expand Down
28 changes: 18 additions & 10 deletions src/auth/__tests__/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ exports[`auth Multifactor Challenge Flow should require MFA Token 1`] = `
]"
`;

exports[`auth OOB flow binding code should be optional 1`] = `{}`;
exports[`auth OOB flow binding code should be optional 1`] = `
{
"accessToken": "1234",
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
}
`;

exports[`auth OOB flow should handle custom parameter 1`] = `
[
Expand Down Expand Up @@ -57,7 +65,7 @@ exports[`auth OOB flow should handle malformed OOB code 1`] = `[invalid_grant: M
exports[`auth OOB flow should handle success with binding code 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand All @@ -67,7 +75,7 @@ exports[`auth OOB flow should handle success with binding code 1`] = `
exports[`auth OOB flow should handle success without binding code 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -121,7 +129,7 @@ exports[`auth OTP flow when MFA is not associated 1`] = `[unsupported_challenge_
exports[`auth OTP flow when MFA succeeds 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -166,7 +174,7 @@ exports[`auth Recovery Code flow should require MFA Token and Recovery Code 1`]
exports[`auth Recovery Code flow when Recovery code succeeds 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -216,7 +224,7 @@ exports[`auth code exchange for native social should handle unexpected error 1`]
exports[`auth code exchange for native social should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand All @@ -226,7 +234,7 @@ exports[`auth code exchange for native social should return successful response
exports[`auth code exchange for native social should return successful response with optional parameters 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -288,7 +296,7 @@ exports[`auth code exchange should handle unexpected error 1`] = `[a0.response.i
exports[`auth code exchange should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -419,7 +427,7 @@ exports[`auth password realm should handle unexpected error 1`] = `[a0.response.
exports[`auth password realm should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -821,7 +829,7 @@ exports[`auth refresh token should handle unknown error 1`] = `[a0.response.inva
exports[`auth refresh token should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down
8 changes: 7 additions & 1 deletion src/auth/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ describe('auth', () => {
};
const auth = new Auth({baseUrl, clientId, telemetry});

beforeAll(() => {
jest
.useFakeTimers()
.setSystemTime(new Date('2023-01-01'));
});

beforeEach(fetchMock.restore);

describe('constructor', () => {
Expand Down Expand Up @@ -875,7 +881,7 @@ describe('auth', () => {
});

it('binding code should be optional', async () => {
fetchMock.postOnce('https://samples.auth0.com/oauth/token', {});
fetchMock.postOnce('https://samples.auth0.com/oauth/token', success);
expect.assertions(1);
await expect(auth.loginWithOOB(parameters)).resolves.toMatchSnapshot();
});
Expand Down
51 changes: 31 additions & 20 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { toCamelCase } from '../utils/camel';
import AuthError from './authError';
import Auth0Error from './auth0Error';
import { Telemetry } from '../networking/telemetry';
import { convertExpiresInToExpiresAt } from '../utils/timestampConversion'
import {
AuthorizeUrlOptions,
CreateUserOptions,
Expand All @@ -28,6 +29,7 @@ import {
UserInfoOptions,
} from '../types';
import {
CredentialsResponse,
RawCredentials,
RawMultifactorChallengeResponse,
RawUser,
Expand All @@ -43,6 +45,15 @@ function responseHandler<TRawResult = unknown, TResult = unknown>(
throw new AuthError(response);
}

function convertTimestampInCredentials(rawCredentials: RawCredentials): Credentials {
let expiresAt = convertExpiresInToExpiresAt(rawCredentials.expiresIn)
if(!expiresAt) {
throw Error('invalid expiry value found')
}
const { expiresIn, ...credentials } = rawCredentials
return {...credentials, expiresAt}
}

/**
* Class for interfacing with the Auth0 Authentication API endpoints.
*
Expand Down Expand Up @@ -144,13 +155,13 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'authorization_code',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -176,14 +187,14 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
);
.then((response) => {
return convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
});
}

/**
Expand All @@ -194,13 +205,13 @@ class Auth {
*/
passwordRealm(parameters: PasswordRealmOptions): Promise<Credentials> {
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...parameters,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/password-realm',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -222,13 +233,13 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'refresh_token',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand Down Expand Up @@ -294,14 +305,14 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
realm: 'email',
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -324,14 +335,14 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
realm: 'sms',
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -356,13 +367,13 @@ class Auth {
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -389,13 +400,13 @@ class Auth {
);

return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-oob',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -422,13 +433,13 @@ class Auth {
);

return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-recovery-code',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand Down
Loading

0 comments on commit ac5d835

Please sign in to comment.